diff options
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/WebPage.cpp')
-rw-r--r-- | Source/WebKit2/WebProcess/WebPage/WebPage.cpp | 3549 |
1 files changed, 2535 insertions, 1014 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp index c7da0d9d2..f5024de4b 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. * Copyright (C) 2012 Intel Corporation. All rights reserved. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) * @@ -28,9 +28,10 @@ #include "config.h" #include "WebPage.h" -#include "Arguments.h" +#include "APIArray.h" +#include "APIGeometry.h" +#include "AssistedNodeInformation.h" #include "DataReference.h" -#include "DecoderAdapter.h" #include "DragControllerAction.h" #include "DrawingArea.h" #include "DrawingAreaMessages.h" @@ -38,19 +39,26 @@ #include "EventDispatcher.h" #include "InjectedBundle.h" #include "InjectedBundleBackForwardList.h" -#include "InjectedBundleUserMessageCoders.h" -#include "LayerTreeHost.h" +#include "InjectedBundleScriptWorld.h" +#include "LibWebRTCProvider.h" +#include "LoadParameters.h" #include "Logging.h" #include "NetscapePlugin.h" #include "NotificationPermissionRequestManager.h" #include "PageBanner.h" -#include "PageOverlay.h" #include "PluginProcessAttributes.h" #include "PluginProxy.h" #include "PluginView.h" #include "PrintInfo.h" +#include "RemoteWebInspectorUI.h" +#include "RemoteWebInspectorUIMessages.h" #include "SessionState.h" +#include "SessionStateConversion.h" +#include "SessionTracker.h" #include "ShareableBitmap.h" +#include "VisitedLinkTableController.h" +#include "WKBundleAPICast.h" +#include "WKRetainPtr.h" #include "WKSharedAPICast.h" #include "WebAlternativeTextClient.h" #include "WebBackForwardListItem.h" @@ -59,64 +67,93 @@ #include "WebColorChooser.h" #include "WebContextMenu.h" #include "WebContextMenuClient.h" -#include "WebContextMessages.h" #include "WebCoreArgumentCoders.h" +#include "WebDatabaseProvider.h" +#include "WebDiagnosticLoggingClient.h" #include "WebDocumentLoader.h" #include "WebDragClient.h" #include "WebEditorClient.h" #include "WebEvent.h" #include "WebEventConversion.h" +#include "WebEventFactory.h" #include "WebFrame.h" #include "WebFrameLoaderClient.h" #include "WebFullScreenManager.h" #include "WebFullScreenManagerMessages.h" +#include "WebGamepadProvider.h" #include "WebGeolocationClient.h" #include "WebImage.h" #include "WebInspector.h" #include "WebInspectorClient.h" #include "WebInspectorMessages.h" +#include "WebInspectorUI.h" +#include "WebInspectorUIMessages.h" +#include "WebMediaKeyStorageManager.h" #include "WebNotificationClient.h" #include "WebOpenPanelResultListener.h" #include "WebPageCreationParameters.h" #include "WebPageGroupProxy.h" #include "WebPageMessages.h" +#include "WebPageOverlay.h" #include "WebPageProxyMessages.h" +#include "WebPaymentCoordinator.h" #include "WebPlugInClient.h" +#include "WebPluginInfoProvider.h" #include "WebPopupMenu.h" +#include "WebPreferencesDefinitions.h" +#include "WebPreferencesKeys.h" #include "WebPreferencesStore.h" #include "WebProcess.h" +#include "WebProcessPoolMessages.h" #include "WebProcessProxyMessages.h" #include "WebProgressTrackerClient.h" +#include "WebSocketProvider.h" +#include "WebStorageNamespaceProvider.h" +#include "WebUndoStep.h" +#include "WebUserContentController.h" +#include "WebUserMediaClient.h" +#include "WebValidationMessageClient.h" #include <JavaScriptCore/APICast.h> +#include <WebCore/ApplicationCacheStorage.h> #include <WebCore/ArchiveResource.h> +#include <WebCore/BackForwardController.h> #include <WebCore/Chrome.h> +#include <WebCore/CommonVM.h> #include <WebCore/ContextMenuController.h> +#include <WebCore/DataTransfer.h> #include <WebCore/DatabaseManager.h> #include <WebCore/DocumentFragment.h> #include <WebCore/DocumentLoader.h> #include <WebCore/DocumentMarkerController.h> #include <WebCore/DragController.h> #include <WebCore/DragData.h> -#include <WebCore/DragSession.h> +#include <WebCore/ElementIterator.h> #include <WebCore/EventHandler.h> +#include <WebCore/EventNames.h> #include <WebCore/FocusController.h> #include <WebCore/FormState.h> #include <WebCore/FrameLoadRequest.h> #include <WebCore/FrameLoaderTypes.h> #include <WebCore/FrameView.h> #include <WebCore/HTMLFormElement.h> +#include <WebCore/HTMLImageElement.h> #include <WebCore/HTMLInputElement.h> +#include <WebCore/HTMLOListElement.h> #include <WebCore/HTMLPlugInElement.h> #include <WebCore/HTMLPlugInImageElement.h> +#include <WebCore/HTMLUListElement.h> #include <WebCore/HistoryController.h> #include <WebCore/HistoryItem.h> #include <WebCore/HitTestResult.h> +#include <WebCore/InspectorController.h> +#include <WebCore/JSDOMExceptionHandling.h> #include <WebCore/JSDOMWindow.h> #include <WebCore/KeyboardEvent.h> #include <WebCore/MIMETypeRegistry.h> #include <WebCore/MainFrame.h> #include <WebCore/MouseEvent.h> #include <WebCore/Page.h> +#include <WebCore/PageConfiguration.h> #include <WebCore/PlatformKeyboardEvent.h> #include <WebCore/PluginDocument.h> #include <WebCore/PrintContext.h> @@ -124,69 +161,89 @@ #include <WebCore/RenderLayer.h> #include <WebCore/RenderTreeAsText.h> #include <WebCore/RenderView.h> -#include <WebCore/ResourceBuffer.h> #include <WebCore/ResourceRequest.h> #include <WebCore/ResourceResponse.h> #include <WebCore/RuntimeEnabledFeatures.h> #include <WebCore/SchemeRegistry.h> #include <WebCore/ScriptController.h> #include <WebCore/SerializedScriptValue.h> +#include <WebCore/SessionID.h> #include <WebCore/Settings.h> #include <WebCore/ShadowRoot.h> #include <WebCore/SharedBuffer.h> +#include <WebCore/StyleProperties.h> #include <WebCore/SubframeLoader.h> #include <WebCore/SubstituteData.h> #include <WebCore/TextIterator.h> +#include <WebCore/UserInputBridge.h> +#include <WebCore/UserScript.h> +#include <WebCore/UserStyleSheet.h> #include <WebCore/VisiblePosition.h> #include <WebCore/VisibleUnits.h> +#include <WebCore/WebGLStateTracker.h> +#include <WebCore/htmlediting.h> #include <WebCore/markup.h> #include <bindings/ScriptValue.h> +#include <profiler/ProfilerDatabase.h> +#include <runtime/JSCInlines.h> #include <runtime/JSCJSValue.h> #include <runtime/JSLock.h> -#include <runtime/Operations.h> +#include <runtime/SamplingProfiler.h> #include <wtf/RunLoop.h> +#include <wtf/SetForScope.h> -#if ENABLE(MHTML) -#include <WebCore/MHTMLArchive.h> -#endif - -#if PLATFORM(MAC) -#include "MachPort.h" +#if ENABLE(DATA_DETECTION) +#include "DataDetectionResult.h" #endif -#if ENABLE(BATTERY_STATUS) -#include "WebBatteryClient.h" -#endif - -#if ENABLE(NETWORK_INFO) -#include "WebNetworkInfoClient.h" +#if ENABLE(MHTML) +#include <WebCore/MHTMLArchive.h> #endif #if ENABLE(VIBRATION) #include "WebVibrationClient.h" #endif +#if ENABLE(POINTER_LOCK) +#include <WebCore/PointerLockController.h> +#endif + #if ENABLE(PROXIMITY_EVENTS) #include "WebDeviceProximityClient.h" #endif -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include "PDFPlugin.h" +#include "RemoteLayerTreeTransaction.h" +#include "WKStringCF.h" +#include "WebPlaybackSessionManager.h" +#include "WebVideoFullscreenManager.h" #include <WebCore/LegacyWebArchive.h> #endif #if PLATFORM(GTK) -#include <gtk/gtk.h> -#include "DataObjectGtk.h" #include "WebPrintOperationGtk.h" +#include "WebSelectionData.h" +#include <gtk/gtk.h> +#endif + +#if PLATFORM(IOS) +#include "RemoteLayerTreeDrawingArea.h" +#include <CoreGraphics/CoreGraphics.h> +#include <WebCore/CoreTextSPI.h> +#include <WebCore/Icon.h> #endif #ifndef NDEBUG #include <wtf/RefCountedLeakCounter.h> #endif -#if USE(COORDINATED_GRAPHICS) -#include "CoordinatedLayerTreeHostMessages.h" +#if ENABLE(DATA_DETECTION) +#include <WebCore/DataDetection.h> +#endif + +#if ENABLE(VIDEO) && USE(GSTREAMER) +#include <WebCore/MediaPlayerRequestInstallMissingPluginsCallback.h> #endif using namespace JSC; @@ -194,6 +251,13 @@ using namespace WebCore; namespace WebKit { +static const double pageScrollHysteresisSeconds = 0.3; +static const std::chrono::milliseconds initialLayerVolatilityTimerInterval { 20 }; +static const std::chrono::seconds maximumLayerVolatilityTimerInterval { 2 }; + +#define RELEASE_LOG_IF_ALLOWED(...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Layers, __VA_ARGS__) +#define RELEASE_LOG_ERROR_IF_ALLOWED(...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Layers, __VA_ARGS__) + class SendStopResponsivenessTimer { public: SendStopResponsivenessTimer(WebPage* page) @@ -210,115 +274,147 @@ private: WebPage* m_page; }; +class DeferredPageDestructor { +public: + static void createDeferredPageDestructor(std::unique_ptr<Page> page, WebPage* webPage) + { + new DeferredPageDestructor(WTFMove(page), webPage); + } + +private: + DeferredPageDestructor(std::unique_ptr<Page> page, WebPage* webPage) + : m_page(WTFMove(page)) + , m_webPage(webPage) + { + tryDestruction(); + } + + void tryDestruction() + { + if (m_page->insideNestedRunLoop()) { + m_page->whenUnnested([this] { tryDestruction(); }); + return; + } + + m_page = nullptr; + m_webPage = nullptr; + delete this; + } + + std::unique_ptr<Page> m_page; + RefPtr<WebPage> m_webPage; +}; + DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageCounter, ("WebPage")); -PassRefPtr<WebPage> WebPage::create(uint64_t pageID, const WebPageCreationParameters& parameters) +Ref<WebPage> WebPage::create(uint64_t pageID, WebPageCreationParameters&& parameters) { - RefPtr<WebPage> page = adoptRef(new WebPage(pageID, parameters)); + Ref<WebPage> page = adoptRef(*new WebPage(pageID, WTFMove(parameters))); - if (page->pageGroup()->isVisibleToInjectedBundle() && WebProcess::shared().injectedBundle()) - WebProcess::shared().injectedBundle()->didCreatePage(page.get()); + if (page->pageGroup()->isVisibleToInjectedBundle() && WebProcess::singleton().injectedBundle()) + WebProcess::singleton().injectedBundle()->didCreatePage(page.ptr()); - return page.release(); + return page; } -WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) +WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters) : m_pageID(pageID) - , m_sessionID(0) , m_viewSize(parameters.viewSize) - , m_hasSeenPlugin(false) - , m_useFixedLayout(false) - , m_drawsBackground(true) - , m_drawsTransparentBackground(false) - , m_isInRedo(false) - , m_isClosed(false) - , m_tabToLinks(false) - , m_asynchronousPluginInitializationEnabled(false) - , m_asynchronousPluginInitializationEnabledForAllPlugins(false) - , m_artificialPluginInitializationDelayEnabled(false) - , m_scrollingPerformanceLoggingEnabled(false) - , m_mainFrameIsScrollable(true) #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) - , m_readyToFindPrimarySnapshottedPlugin(false) - , m_didFindPrimarySnapshottedPlugin(false) - , m_numberOfPrimarySnapshotDetectionAttempts(0) , m_determinePrimarySnapshottedPlugInTimer(RunLoop::main(), this, &WebPage::determinePrimarySnapshottedPlugInTimerFired) #endif , m_layerHostingMode(parameters.layerHostingMode) -#if PLATFORM(MAC) - , m_pdfPluginEnabled(false) - , m_hasCachedWindowFrame(false) - , m_keyboardEventBeingInterpreted(0) -#if !PLATFORM(IOS) +#if PLATFORM(COCOA) , m_viewGestureGeometryCollector(*this) -#endif -#elif PLATFORM(GTK) && HAVE(ACCESSIBILITY) - , m_accessibilityObject(0) +#elif HAVE(ACCESSIBILITY) && PLATFORM(GTK) + , m_accessibilityObject(nullptr) #endif , m_setCanStartMediaTimer(RunLoop::main(), this, &WebPage::setCanStartMediaTimerFired) - , m_sendDidUpdateViewStateTimer(RunLoop::main(), this, &WebPage::didUpdateViewStateTimerFired) - , m_findController(this) -#if ENABLE(INPUT_TYPE_COLOR) - , m_activeColorChooser(0) +#if ENABLE(CONTEXT_MENUS) + , m_contextMenuClient(std::make_unique<API::InjectedBundle::PageContextMenuClient>()) #endif + , m_editorClient { std::make_unique<API::InjectedBundle::EditorClient>() } + , m_formClient(std::make_unique<API::InjectedBundle::FormClient>()) + , m_uiClient(std::make_unique<API::InjectedBundle::PageUIClient>()) + , m_findController(this) + , m_userContentController(WebUserContentController::getOrCreate(parameters.userContentControllerID)) #if ENABLE(GEOLOCATION) , m_geolocationPermissionRequestManager(this) #endif +#if ENABLE(MEDIA_STREAM) + , m_userMediaPermissionRequestManager(*this) +#endif + , m_pageScrolledHysteresis([this](HysteresisState state) { if (state == HysteresisState::Stopped) pageStoppedScrolling(); }, pageScrollHysteresisSeconds) , m_canRunBeforeUnloadConfirmPanel(parameters.canRunBeforeUnloadConfirmPanel) , m_canRunModal(parameters.canRunModal) - , m_isRunningModal(false) - , m_cachedMainFrameIsPinnedToLeftSide(false) - , m_cachedMainFrameIsPinnedToRightSide(false) - , m_cachedMainFrameIsPinnedToTopSide(false) - , m_cachedMainFrameIsPinnedToBottomSide(false) - , m_canShortCircuitHorizontalWheelEvents(false) - , m_numWheelEventHandlers(0) - , m_cachedPageCount(0) - , m_autoSizingShouldExpandToViewHeight(false) -#if ENABLE(CONTEXT_MENUS) - , m_isShowingContextMenu(false) -#endif #if PLATFORM(IOS) - , m_shouldReturnWordAtSelection(false) -#endif - , m_inspectorClient(0) - , m_backgroundColor(Color::white) - , m_maximumRenderingSuppressionToken(0) - , m_scrollPinningBehavior(DoNotPin) - , m_useAsyncScrolling(false) - , m_viewState(parameters.viewState) - , m_processSuppressionDisabledByWebPreference("Process suppression is disabled.") + , m_forceAlwaysUserScalable(parameters.ignoresViewportScaleLimits) + , m_screenSize(parameters.screenSize) + , m_availableScreenSize(parameters.availableScreenSize) +#endif + , m_layerVolatilityTimer(*this, &WebPage::layerVolatilityTimerFired) + , m_activityState(parameters.activityState) + , m_processSuppressionEnabled(true) + , m_userActivity("Process suppression disabled for page.") + , m_userActivityHysteresis([this](HysteresisState) { updateUserActivity(); }) + , m_userInterfaceLayoutDirection(parameters.userInterfaceLayoutDirection) + , m_overrideContentSecurityPolicy { parameters.overrideContentSecurityPolicy } { ASSERT(m_pageID); - // FIXME: This is a non-ideal location for this Setting and - // 4ms should be adopted project-wide now, https://bugs.webkit.org/show_bug.cgi?id=61214 - Settings::setDefaultMinDOMTimerInterval(0.004); - Page::PageClients pageClients; - pageClients.chromeClient = new WebChromeClient(this); + m_pageGroup = WebProcess::singleton().webPageGroup(parameters.pageGroupData); + +#if PLATFORM(IOS) + Settings::setShouldManageAudioSessionCategory(true); +#endif + + PageConfiguration pageConfiguration( + makeUniqueRef<WebEditorClient>(this), + WebSocketProvider::create(), + makeUniqueRef<WebKit::LibWebRTCProvider>() + ); + pageConfiguration.chromeClient = new WebChromeClient(*this); #if ENABLE(CONTEXT_MENUS) - pageClients.contextMenuClient = new WebContextMenuClient(this); + pageConfiguration.contextMenuClient = new WebContextMenuClient(this); #endif - pageClients.editorClient = new WebEditorClient(this); #if ENABLE(DRAG_SUPPORT) - pageClients.dragClient = new WebDragClient(this); -#endif - pageClients.backForwardClient = WebBackForwardListProxy::create(this); -#if ENABLE(INSPECTOR) - m_inspectorClient = new WebInspectorClient(this); - pageClients.inspectorClient = m_inspectorClient; + pageConfiguration.dragClient = new WebDragClient(this); #endif + pageConfiguration.backForwardClient = WebBackForwardListProxy::create(this); + pageConfiguration.inspectorClient = new WebInspectorClient(this); #if USE(AUTOCORRECTION_PANEL) - pageClients.alternativeTextClient = new WebAlternativeTextClient(this); + pageConfiguration.alternativeTextClient = new WebAlternativeTextClient(this); #endif - pageClients.plugInClient = new WebPlugInClient(this); - pageClients.loaderClientForMainFrame = new WebFrameLoaderClient; - pageClients.progressTrackerClient = new WebProgressTrackerClient(*this); - m_page = adoptPtr(new Page(pageClients)); + pageConfiguration.plugInClient = new WebPlugInClient(*this); + pageConfiguration.loaderClientForMainFrame = new WebFrameLoaderClient; + pageConfiguration.progressTrackerClient = new WebProgressTrackerClient(*this); + pageConfiguration.diagnosticLoggingClient = std::make_unique<WebDiagnosticLoggingClient>(*this); + pageConfiguration.webGLStateTracker = std::make_unique<WebGLStateTracker>([this](bool isUsingHighPerformanceWebGL) { + send(Messages::WebPageProxy::SetIsUsingHighPerformanceWebGL(isUsingHighPerformanceWebGL)); + }); + +#if PLATFORM(COCOA) + pageConfiguration.validationMessageClient = std::make_unique<WebValidationMessageClient>(*this); +#endif + + pageConfiguration.applicationCacheStorage = &WebProcess::singleton().applicationCacheStorage(); + pageConfiguration.databaseProvider = WebDatabaseProvider::getOrCreate(m_pageGroup->pageGroupID()); + pageConfiguration.pluginInfoProvider = &WebPluginInfoProvider::singleton(); + pageConfiguration.storageNamespaceProvider = WebStorageNamespaceProvider::getOrCreate(m_pageGroup->pageGroupID()); + pageConfiguration.userContentProvider = m_userContentController.ptr(); + pageConfiguration.visitedLinkStore = VisitedLinkTableController::getOrCreate(parameters.visitedLinkTableID); + +#if ENABLE(APPLE_PAY) + pageConfiguration.paymentCoordinatorClient = new WebPaymentCoordinator(*this); +#endif - m_drawingArea = DrawingArea::create(this, parameters); + m_page = std::make_unique<Page>(WTFMove(pageConfiguration)); + updatePreferences(parameters.store); + + m_drawingArea = DrawingArea::create(*this, parameters); m_drawingArea->setPaintingEnabled(false); + m_drawingArea->setShouldScaleViewToFitDocument(parameters.shouldScaleViewToFitDocument); #if ENABLE(ASYNC_SCROLLING) m_useAsyncScrolling = parameters.store.getBoolValueForKey(WebPreferencesKey::threadedScrollingEnabledKey()); @@ -328,16 +424,11 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) #endif m_mainFrame = WebFrame::createWithCoreMainFrame(this, &m_page->mainFrame()); + m_drawingArea->updatePreferences(parameters.store); -#if ENABLE(BATTERY_STATUS) - WebCore::provideBatteryTo(m_page.get(), new WebBatteryClient(this)); -#endif #if ENABLE(GEOLOCATION) WebCore::provideGeolocationTo(m_page.get(), new WebGeolocationClient(this)); #endif -#if ENABLE(NETWORK_INFO) - WebCore::provideNetworkInfoTo(m_page.get(), new WebNetworkInfoClient(this)); -#endif #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) WebCore::provideNotification(m_page.get(), new WebNotificationClient(this)); #endif @@ -347,25 +438,32 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) #if ENABLE(PROXIMITY_EVENTS) WebCore::provideDeviceProximityTo(m_page.get(), new WebDeviceProximityClient(this)); #endif +#if ENABLE(MEDIA_STREAM) + WebCore::provideUserMediaTo(m_page.get(), new WebUserMediaClient(*this)); +#endif + + m_page->setControlledByAutomation(parameters.controlledByAutomation); #if ENABLE(REMOTE_INSPECTOR) - m_page->setRemoteInspectionAllowed(true); + m_page->setRemoteInspectionAllowed(parameters.allowsRemoteInspection); + m_page->setRemoteInspectionNameOverride(parameters.remoteInspectionNameOverride); #endif m_page->setCanStartMedia(false); m_mayStartMediaWhenInWindow = parameters.mayStartMediaWhenInWindow; - m_pageGroup = WebProcess::shared().webPageGroup(parameters.pageGroupData); m_page->setGroupName(m_pageGroup->identifier()); m_page->setDeviceScaleFactor(parameters.deviceScaleFactor); + m_page->setUserInterfaceLayoutDirection(m_userInterfaceLayoutDirection); +#if PLATFORM(IOS) + m_page->setTextAutosizingWidth(parameters.textAutosizingWidth); +#endif - updatePreferences(parameters.store); platformInitialize(); setUseFixedLayout(parameters.useFixedLayout); setDrawsBackground(parameters.drawsBackground); - setDrawsTransparentBackground(parameters.drawsTransparentBackground); setUnderlayColor(parameters.underlayColor); @@ -373,53 +471,56 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) setPaginationBehavesLikeColumns(parameters.paginationBehavesLikeColumns); setPageLength(parameters.pageLength); setGapBetweenPages(parameters.gapBetweenPages); + setPaginationLineGridEnabled(parameters.paginationLineGridEnabled); + + // If the page is created off-screen, its visibilityState should be prerender. + m_page->setActivityState(m_activityState); + if (!isVisible()) + m_page->setIsPrerender(); - setMemoryCacheMessagesEnabled(parameters.areMemoryCacheClientCallsEnabled); - - setActive(parameters.viewState & ViewState::WindowIsActive); - setFocused(parameters.viewState & ViewState::IsFocused); - - // Page defaults to in-window, but setIsInWindow depends on it being a valid indicator of actually having been put into a window. - bool isInWindow = parameters.viewState & ViewState::IsInWindow; - if (!isInWindow) - m_page->setIsInWindow(false); - else - WebProcess::shared().pageDidEnterWindow(m_pageID); - - setIsInWindow(isInWindow); + updateIsInWindow(true); setMinimumLayoutSize(parameters.minimumLayoutSize); setAutoSizingShouldExpandToViewHeight(parameters.autoSizingShouldExpandToViewHeight); setScrollPinningBehavior(parameters.scrollPinningBehavior); + if (parameters.scrollbarOverlayStyle) + m_scrollbarOverlayStyle = static_cast<ScrollbarOverlayStyle>(parameters.scrollbarOverlayStyle.value()); + else + m_scrollbarOverlayStyle = std::optional<ScrollbarOverlayStyle>(); + setBackgroundExtendsBeyondPage(parameters.backgroundExtendsBeyondPage); + setTopContentInset(parameters.topContentInset); + m_userAgent = parameters.userAgent; WebBackForwardListProxy::setHighestItemIDFromUIProcess(parameters.highestUsedBackForwardItemID); - if (!parameters.sessionState.isEmpty()) - restoreSession(parameters.sessionState); + if (!parameters.itemStates.isEmpty()) + restoreSessionInternal(parameters.itemStates, WasRestoredByAPIRequest::No); + + if (parameters.sessionID.isValid()) + setSessionID(parameters.sessionID); m_drawingArea->setPaintingEnabled(true); setMediaVolume(parameters.mediaVolume); - // We use the DidFirstLayout milestone to determine when to unfreeze the layer tree. - m_page->addLayoutMilestones(DidFirstLayout); + setMuted(parameters.muted); + + // We use the DidFirstVisuallyNonEmptyLayout milestone to determine when to unfreeze the layer tree. + m_page->addLayoutMilestones(DidFirstLayout | DidFirstVisuallyNonEmptyLayout); - WebProcess::shared().addMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID, *this); + auto& webProcess = WebProcess::singleton(); + webProcess.addMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID, *this); // FIXME: This should be done in the object constructors, and the objects themselves should be message receivers. - WebProcess::shared().addMessageReceiver(Messages::DrawingArea::messageReceiverName(), m_pageID, *this); -#if USE(COORDINATED_GRAPHICS) - WebProcess::shared().addMessageReceiver(Messages::CoordinatedLayerTreeHost::messageReceiverName(), m_pageID, *this); -#endif -#if ENABLE(INSPECTOR) - WebProcess::shared().addMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID, *this); -#endif + webProcess.addMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID, *this); + webProcess.addMessageReceiver(Messages::WebInspectorUI::messageReceiverName(), m_pageID, *this); + webProcess.addMessageReceiver(Messages::RemoteWebInspectorUI::messageReceiverName(), m_pageID, *this); #if ENABLE(FULLSCREEN_API) - WebProcess::shared().addMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID, *this); + webProcess.addMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID, *this); #endif #ifndef NDEBUG @@ -428,21 +529,61 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) #if ENABLE(ASYNC_SCROLLING) if (m_useAsyncScrolling) - WebProcess::shared().eventDispatcher().addScrollingTreeForPage(this); + webProcess.eventDispatcher().addScrollingTreeForPage(this); +#endif + + for (auto& mimeType : parameters.mimeTypesWithCustomContentProviders) + m_mimeTypesWithCustomContentProviders.add(mimeType); + + +#if ENABLE(LEGACY_ENCRYPTED_MEDIA) + if (WebMediaKeyStorageManager* manager = webProcess.supplement<WebMediaKeyStorageManager>()) + m_page->settings().setMediaKeysStorageDirectory(manager->mediaKeyStorageDirectory()); #endif + m_page->settings().setAppleMailPaginationQuirkEnabled(parameters.appleMailPaginationQuirkEnabled); - m_page->setIsVisible(m_viewState & ViewState::IsVisible, true); - setIsVisuallyIdle(m_viewState & ViewState::IsVisuallyIdle); + if (parameters.viewScaleFactor != 1) + scaleView(parameters.viewScaleFactor); + + m_page->addLayoutMilestones(parameters.observedLayoutMilestones); + +#if PLATFORM(COCOA) + m_page->settings().setContentDispositionAttachmentSandboxEnabled(true); + setSmartInsertDeleteEnabled(parameters.smartInsertDeleteEnabled); +#endif } -void WebPage::reinitializeWebPage(const WebPageCreationParameters& parameters) +void WebPage::reinitializeWebPage(WebPageCreationParameters&& parameters) { - if (m_viewState != parameters.viewState) - setViewStateInternal(parameters.viewState, true); + if (m_activityState != parameters.activityState) + setActivityState(parameters.activityState, false, Vector<uint64_t>()); if (m_layerHostingMode != parameters.layerHostingMode) setLayerHostingMode(parameters.layerHostingMode); } +void WebPage::updateThrottleState() +{ + // We should suppress if the page is not active, is visually idle, and supression is enabled. + bool isLoading = m_activityState & ActivityState::IsLoading; + bool isPlayingAudio = m_activityState & ActivityState::IsAudible; + bool pageSuppressed = !isLoading && !isPlayingAudio && m_processSuppressionEnabled && (m_activityState & ActivityState::IsVisuallyIdle); + + // The UserActivity keeps the processes runnable. So if the page should be suppressed, stop the activity. + // If the page should not be supressed, start it. + if (pageSuppressed) + m_userActivityHysteresis.stop(); + else + m_userActivityHysteresis.start(); +} + +void WebPage::updateUserActivity() +{ + if (m_userActivityHysteresis.state() == HysteresisState::Started) + m_userActivity.start(); + else + m_userActivity.stop(); +} + WebPage::~WebPage() { if (m_backForwardList) @@ -450,11 +591,14 @@ WebPage::~WebPage() ASSERT(!m_page); + auto& webProcess = WebProcess::singleton(); #if ENABLE(ASYNC_SCROLLING) if (m_useAsyncScrolling) - WebProcess::shared().eventDispatcher().removeScrollingTreeForPage(this); + webProcess.eventDispatcher().removeScrollingTreeForPage(this); #endif + platformDetach(); + m_sandboxExtensionTracker.invalidate(); for (auto* pluginView : m_pluginViews) @@ -467,18 +611,14 @@ WebPage::~WebPage() m_footerBanner->detachFromPage(); #endif // !PLATFORM(IOS) - WebProcess::shared().removeMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID); + webProcess.removeMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID); // FIXME: This should be done in the object destructors, and the objects themselves should be message receivers. - WebProcess::shared().removeMessageReceiver(Messages::DrawingArea::messageReceiverName(), m_pageID); -#if USE(COORDINATED_GRAPHICS) - WebProcess::shared().removeMessageReceiver(Messages::CoordinatedLayerTreeHost::messageReceiverName(), m_pageID); -#endif -#if ENABLE(INSPECTOR) - WebProcess::shared().removeMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID); -#endif + webProcess.removeMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID); + webProcess.removeMessageReceiver(Messages::WebInspectorUI::messageReceiverName(), m_pageID); + webProcess.removeMessageReceiver(Messages::RemoteWebInspectorUI::messageReceiverName(), m_pageID); #if ENABLE(FULLSCREEN_API) - WebProcess::shared().removeMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID); + webProcess.removeMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID); #endif #ifndef NDEBUG @@ -492,7 +632,7 @@ void WebPage::dummy(bool&) IPC::Connection* WebPage::messageSenderConnection() { - return WebProcess::shared().parentProcessConnection(); + return WebProcess::singleton().parentProcessConnection(); } uint64_t WebPage::messageSenderDestinationID() @@ -501,20 +641,35 @@ uint64_t WebPage::messageSenderDestinationID() } #if ENABLE(CONTEXT_MENUS) -void WebPage::initializeInjectedBundleContextMenuClient(WKBundlePageContextMenuClientBase* client) +void WebPage::setInjectedBundleContextMenuClient(std::unique_ptr<API::InjectedBundle::PageContextMenuClient> contextMenuClient) { - m_contextMenuClient.initialize(client); + if (!contextMenuClient) { + m_contextMenuClient = std::make_unique<API::InjectedBundle::PageContextMenuClient>(); + return; + } + + m_contextMenuClient = WTFMove(contextMenuClient); } #endif -void WebPage::initializeInjectedBundleEditorClient(WKBundlePageEditorClientBase* client) +void WebPage::setInjectedBundleEditorClient(std::unique_ptr<API::InjectedBundle::EditorClient> editorClient) { - m_editorClient.initialize(client); + if (!editorClient) { + m_editorClient = std::make_unique<API::InjectedBundle::EditorClient>(); + return; + } + + m_editorClient = WTFMove(editorClient); } -void WebPage::initializeInjectedBundleFormClient(WKBundlePageFormClientBase* client) +void WebPage::setInjectedBundleFormClient(std::unique_ptr<API::InjectedBundle::FormClient> formClient) { - m_formClient.initialize(client); + if (!formClient) { + m_formClient = std::make_unique<API::InjectedBundle::FormClient>(); + return; + } + + m_formClient = WTFMove(formClient); } void WebPage::initializeInjectedBundleLoaderClient(WKBundlePageLoaderClientBase* client) @@ -546,9 +701,14 @@ void WebPage::initializeInjectedBundleResourceLoadClient(WKBundlePageResourceLoa m_resourceLoadClient.initialize(client); } -void WebPage::initializeInjectedBundleUIClient(WKBundlePageUIClientBase* client) +void WebPage::setInjectedBundleUIClient(std::unique_ptr<API::InjectedBundle::PageUIClient> uiClient) { - m_uiClient.initialize(client); + if (!uiClient) { + m_uiClient = std::make_unique<API::InjectedBundle::PageUIClient>(); + return; + } + + m_uiClient = WTFMove(uiClient); } #if ENABLE(FULLSCREEN_API) @@ -558,19 +718,22 @@ void WebPage::initializeInjectedBundleFullScreenClient(WKBundlePageFullScreenCli } #endif -void WebPage::initializeInjectedBundleDiagnosticLoggingClient(WKBundlePageDiagnosticLoggingClientBase* client) -{ - m_logDiagnosticMessageClient.initialize(client); -} - #if ENABLE(NETSCAPE_PLUGIN_API) -PassRefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginElement, const Plugin::Parameters& parameters, String& newMIMEType) + +RefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginElement, const Plugin::Parameters& parameters, String& newMIMEType) { String frameURLString = frame->coreFrame()->loader().documentLoader()->responseURL().string(); String pageURLString = m_page->mainFrame().loader().documentLoader()->responseURL().string(); + +#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) + HTMLPlugInImageElement& pluginImageElement = downcast<HTMLPlugInImageElement>(*pluginElement); + unsigned pluginArea = 0; + PluginProcessType processType = pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot && !(plugInIsPrimarySize(pluginImageElement, pluginArea) && !plugInIntersectsSearchRect(pluginImageElement)) ? PluginProcessTypeSnapshot : PluginProcessTypeNormal; +#else PluginProcessType processType = pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot ? PluginProcessTypeSnapshot : PluginProcessTypeNormal; +#endif - bool allowOnlyApplicationPlugins = !frame->coreFrame()->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin); + bool allowOnlyApplicationPlugins = !frame->coreFrame()->loader().subframeLoader().allowPlugins(); uint64_t pluginProcessToken; uint32_t pluginLoadPolicy; @@ -578,14 +741,15 @@ PassRefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* plu if (!sendSync(Messages::WebPageProxy::FindPlugin(parameters.mimeType, static_cast<uint32_t>(processType), parameters.url.string(), frameURLString, pageURLString, allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription))) return nullptr; - bool isBlockedPlugin = static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy) == PluginModuleBlocked; + PluginModuleLoadPolicy loadPolicy = static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy); + bool isBlockedPlugin = (loadPolicy == PluginModuleBlockedForSecurity) || (loadPolicy == PluginModuleBlockedForCompatibility); if (isBlockedPlugin || !pluginProcessToken) { #if ENABLE(PDFKIT_PLUGIN) String path = parameters.url.path(); if (shouldUsePDFPlugin() && (MIMETypeRegistry::isPDFOrPostScriptMIMEType(parameters.mimeType) || (parameters.mimeType.isEmpty() && (path.endsWith(".pdf", false) || path.endsWith(".ps", false))))) { - RefPtr<PDFPlugin> pdfPlugin = PDFPlugin::create(frame); - return pdfPlugin.release(); + auto pdfPlugin = PDFPlugin::create(frame); + return WTFMove(pdfPlugin); } #else UNUSED_PARAM(frame); @@ -594,11 +758,12 @@ PassRefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* plu if (isBlockedPlugin) { bool replacementObscured = false; - if (pluginElement->renderer()->isEmbeddedObject()) { - RenderEmbeddedObject* renderObject = toRenderEmbeddedObject(pluginElement->renderer()); - renderObject->setPluginUnavailabilityReasonWithDescription(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription); - replacementObscured = renderObject->isReplacementObscured(); - renderObject->setUnavailablePluginIndicatorIsHidden(replacementObscured); + auto* renderer = pluginElement->renderer(); + if (is<RenderEmbeddedObject>(renderer)) { + auto& renderObject = downcast<RenderEmbeddedObject>(*renderer); + renderObject.setPluginUnavailabilityReasonWithDescription(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription); + replacementObscured = renderObject.isReplacementObscured(); + renderObject.setUnavailablePluginIndicatorIsHidden(replacementObscured); } send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, replacementObscured)); @@ -614,19 +779,19 @@ PassRefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* plu #endif // ENABLE(NETSCAPE_PLUGIN_API) -#if ENABLE(WEBGL) -WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame* frame, const String& url) +#if ENABLE(WEBGL) && !PLATFORM(COCOA) +WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame*, const String& /* url */) { - uint32_t policyResult = 0; - - if (sendSync(Messages::WebPageProxy::WebGLPolicyForURL(url), Messages::WebPageProxy::WebGLPolicyForURL::Reply(policyResult))) - return static_cast<WebGLLoadPolicy>(policyResult); + return WebGLAllowCreation; +} - return WebGLAllow; +WebCore::WebGLLoadPolicy WebPage::resolveWebGLPolicyForURL(WebFrame*, const String& /* url */) +{ + return WebGLAllowCreation; } -#endif // ENABLE(WEBGL) +#endif -EditorState WebPage::editorState() const +EditorState WebPage::editorState(IncludePostLayoutDataHint shouldIncludePostLayoutData) const { Frame& frame = m_page->focusController().focusedOrMainFrame(); @@ -641,49 +806,102 @@ EditorState WebPage::editorState() const } } - result.selectionIsNone = frame.selection().isNone(); - result.selectionIsRange = frame.selection().isRange(); - result.isContentEditable = frame.selection().isContentEditable(); - result.isContentRichlyEditable = frame.selection().isContentRichlyEditable(); - result.isInPasswordField = frame.selection().isInPasswordField(); + const VisibleSelection& selection = frame.selection().selection(); + + result.selectionIsNone = selection.isNone(); + result.selectionIsRange = selection.isRange(); + result.isContentEditable = selection.isContentEditable(); + result.isContentRichlyEditable = selection.isContentRichlyEditable(); + result.isInPasswordField = selection.isInPasswordField(); result.hasComposition = frame.editor().hasComposition(); result.shouldIgnoreCompositionSelectionChange = frame.editor().ignoreCompositionSelectionChange(); -#if PLATFORM(IOS) - FrameSelection& selection = frame.selection(); - if (frame.editor().hasComposition()) { - RefPtr<Range> compositionRange = frame.editor().compositionRange(); - Vector<WebCore::SelectionRect> compositionRects; - compositionRange->collectSelectionRects(compositionRects); - if (compositionRects.size()) - result.firstMarkedRect = compositionRects[0].rect(); - if (compositionRects.size() > 1) - result.lastMarkedRect = compositionRects.last().rect(); - else - result.lastMarkedRect = result.firstMarkedRect; - result.markedText = plainText(compositionRange.get()); - } - if (selection.isCaret()) { - result.caretRectAtStart = selection.absoluteCaretBounds(); - result.caretRectAtEnd = result.caretRectAtStart; - if (m_shouldReturnWordAtSelection) - result.wordAtSelection = plainText(wordRangeFromPosition(selection.start()).get()); - } else if (selection.isRange()) { - result.caretRectAtStart = VisiblePosition(selection.start()).absoluteCaretBounds(); - result.caretRectAtEnd = VisiblePosition(selection.end()).absoluteCaretBounds(); - RefPtr<Range> selectedRange = selection.toNormalizedRange(); - selectedRange->collectSelectionRects(result.selectionRects); - result.selectedTextLength = plainText(selectedRange.get(), TextIteratorDefaultBehavior, true).length(); +#if PLATFORM(COCOA) + if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::Yes && result.isContentEditable) { + auto& postLayoutData = result.postLayoutData(); + if (!selection.isNone()) { + Node* nodeToRemove; + if (auto* style = Editor::styleForSelectionStart(&frame, nodeToRemove)) { + if (style->fontCascade().weight() >= FontWeightBold) + postLayoutData.typingAttributes |= AttributeBold; + if (style->fontCascade().italic() == FontItalicOn) + postLayoutData.typingAttributes |= AttributeItalics; + + RefPtr<EditingStyle> typingStyle = frame.selection().typingStyle(); + if (typingStyle && typingStyle->style()) { + String value = typingStyle->style()->getPropertyValue(CSSPropertyWebkitTextDecorationsInEffect); + if (value.contains("underline")) + postLayoutData.typingAttributes |= AttributeUnderline; + } else { + if (style->textDecorationsInEffect() & TextDecorationUnderline) + postLayoutData.typingAttributes |= AttributeUnderline; + } + + if (style->visitedDependentColor(CSSPropertyColor).isValid()) + postLayoutData.textColor = style->visitedDependentColor(CSSPropertyColor); + + switch (style->textAlign()) { + case RIGHT: + case WEBKIT_RIGHT: + postLayoutData.textAlignment = RightAlignment; + break; + case LEFT: + case WEBKIT_LEFT: + postLayoutData.textAlignment = LeftAlignment; + break; + case CENTER: + case WEBKIT_CENTER: + postLayoutData.textAlignment = CenterAlignment; + break; + case JUSTIFY: + postLayoutData.textAlignment = JustifiedAlignment; + break; + case TASTART: + postLayoutData.textAlignment = style->isLeftToRightDirection() ? LeftAlignment : RightAlignment; + break; + case TAEND: + postLayoutData.textAlignment = style->isLeftToRightDirection() ? RightAlignment : LeftAlignment; + break; + } + + HTMLElement* enclosingListElement = enclosingList(selection.start().deprecatedNode()); + if (enclosingListElement) { + if (is<HTMLUListElement>(*enclosingListElement)) + postLayoutData.enclosingListType = UnorderedList; + else if (is<HTMLOListElement>(*enclosingListElement)) + postLayoutData.enclosingListType = OrderedList; + else + ASSERT_NOT_REACHED(); + } else + postLayoutData.enclosingListType = NoList; + + if (nodeToRemove) + nodeToRemove->remove(); + } + } } #endif -#if PLATFORM(GTK) - result.cursorRect = frame.selection().absoluteCaretBounds(); -#endif + platformEditorState(frame, result, shouldIncludePostLayoutData); + + m_lastEditorStateWasContentEditable = result.isContentEditable ? EditorStateIsContentEditable::Yes : EditorStateIsContentEditable::No; return result; } +void WebPage::updateEditorStateAfterLayoutIfEditabilityChanged() +{ + // FIXME: We should update EditorStateIsContentEditable to track whether the state is richly + // editable or plainttext-only. + if (m_lastEditorStateWasContentEditable == EditorStateIsContentEditable::Unset) + return; + + Frame& frame = m_page->focusController().focusedOrMainFrame(); + EditorStateIsContentEditable editorStateIsContentEditable = frame.selection().selection().isContentEditable() ? EditorStateIsContentEditable::Yes : EditorStateIsContentEditable::No; + if (m_lastEditorStateWasContentEditable != editorStateIsContentEditable) + send(Messages::WebPageProxy::EditorStateChanged(editorState())); +} + String WebPage::renderTreeExternalRepresentation() const { return externalRepresentation(m_mainFrame->coreFrame(), RenderAsTextBehaviorNormal); @@ -721,7 +939,7 @@ void WebPage::resetTrackedRepaints() view->resetTrackedRepaints(); } -PassRefPtr<API::Array> WebPage::trackedRepaintRects() +Ref<API::Array> WebPage::trackedRepaintRects() { FrameView* view = mainFrameView(); if (!view) @@ -733,7 +951,7 @@ PassRefPtr<API::Array> WebPage::trackedRepaintRects() for (const auto& repaintRect : view->trackedRepaintRects()) repaintRects.uncheckedAppend(API::Rect::create(toAPI(repaintRect))); - return API::Array::create(std::move(repaintRects)); + return API::Array::create(WTFMove(repaintRects)); } PluginView* WebPage::focusedPluginViewForFrame(Frame& frame) @@ -772,6 +990,19 @@ void WebPage::executeEditingCommand(const String& commandName, const String& arg frame.editor().command(commandName).execute(argument); } +void WebPage::setEditable(bool editable) +{ + m_page->setEditable(editable); + m_page->setTabKeyCyclesThroughElements(!editable); + Frame& frame = m_page->focusController().focusedOrMainFrame(); + if (editable) { + frame.editor().applyEditingStyleToBodyElement(); + // If the page is made editable and the selection is empty, set it to something. + if (frame.selection().isNone()) + frame.selection().setSelectionFromNone(); + } +} + bool WebPage::isEditingCommandEnabled(const String& commandName) { Frame& frame = m_page->focusController().focusedOrMainFrame(); @@ -789,7 +1020,6 @@ void WebPage::clearMainFrameName() frame->tree().clearName(); } -#if USE(ACCELERATED_COMPOSITING) void WebPage::enterAcceleratedCompositingMode(GraphicsLayer* layer) { m_drawingArea->setRootCompositingLayer(layer); @@ -799,7 +1029,6 @@ void WebPage::exitAcceleratedCompositingMode() { m_drawingArea->setRootCompositingLayer(0); } -#endif void WebPage::close() { @@ -812,30 +1041,34 @@ void WebPage::close() if (!mainWebFrame()->url().isEmpty()) reportUsedFeatures(); - if (pageGroup()->isVisibleToInjectedBundle() && WebProcess::shared().injectedBundle()) - WebProcess::shared().injectedBundle()->willDestroyPage(this); + if (pageGroup()->isVisibleToInjectedBundle() && WebProcess::singleton().injectedBundle()) + WebProcess::singleton().injectedBundle()->willDestroyPage(this); + + if (m_inspector) { + m_inspector->disconnectFromPage(); + m_inspector = nullptr; + } + + m_page->inspectorController().disconnectAllFrontends(); -#if ENABLE(INSPECTOR) - m_inspector = 0; -#endif #if ENABLE(FULLSCREEN_API) - m_fullScreenManager = 0; + m_fullScreenManager = nullptr; #endif if (m_activePopupMenu) { m_activePopupMenu->disconnectFromPage(); - m_activePopupMenu = 0; + m_activePopupMenu = nullptr; } if (m_activeOpenPanelResultListener) { m_activeOpenPanelResultListener->disconnectFromPage(); - m_activeOpenPanelResultListener = 0; + m_activeOpenPanelResultListener = nullptr; } #if ENABLE(INPUT_TYPE_COLOR) if (m_activeColorChooser) { m_activeColorChooser->disconnectFromPage(); - m_activeColorChooser = 0; + m_activeColorChooser = nullptr; } #endif @@ -846,6 +1079,13 @@ void WebPage::close() } #endif +#if ENABLE(VIDEO) && USE(GSTREAMER) + if (m_installMediaPluginsCallback) { + m_installMediaPluginsCallback->invalidate(); + m_installMediaPluginsCallback = nullptr; + } +#endif + m_sandboxExtensionTracker.invalidate(); #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) @@ -853,39 +1093,41 @@ void WebPage::close() #endif #if ENABLE(CONTEXT_MENUS) - m_contextMenuClient.initialize(0); + m_contextMenuClient = std::make_unique<API::InjectedBundle::PageContextMenuClient>(); #endif - m_editorClient.initialize(0); - m_formClient.initialize(0); + m_editorClient = std::make_unique<API::InjectedBundle::EditorClient>(); + m_formClient = std::make_unique<API::InjectedBundle::FormClient>(); m_loaderClient.initialize(0); m_policyClient.initialize(0); m_resourceLoadClient.initialize(0); - m_uiClient.initialize(0); + m_uiClient = std::make_unique<API::InjectedBundle::PageUIClient>(); #if ENABLE(FULLSCREEN_API) m_fullScreenClient.initialize(0); #endif - m_logDiagnosticMessageClient.initialize(0); m_printContext = nullptr; m_mainFrame->coreFrame()->loader().detachFromParent(); - m_page = nullptr; m_drawingArea = nullptr; + DeferredPageDestructor::createDeferredPageDestructor(WTFMove(m_page), this); + bool isRunningModal = m_isRunningModal; m_isRunningModal = false; // The WebPage can be destroyed by this call. - WebProcess::shared().removeWebPage(m_pageID); + WebProcess::singleton().removeWebPage(m_pageID); + + WebProcess::singleton().updateActivePages(); if (isRunningModal) - RunLoop::main()->stop(); + RunLoop::main().stop(); } void WebPage::tryClose() { SendStopResponsivenessTimer stopper(this); - if (!m_mainFrame->coreFrame()->loader().shouldClose()) { + if (!corePage()->userInputBridge().tryClosePage()) { send(Messages::WebPageProxy::StopResponsivenessTimer()); return; } @@ -900,108 +1142,137 @@ void WebPage::sendClose() void WebPage::loadURLInFrame(const String& url, uint64_t frameID) { - WebFrame* frame = WebProcess::shared().webFrame(frameID); + WebFrame* frame = WebProcess::singleton().webFrame(frameID); if (!frame) return; - frame->coreFrame()->loader().load(FrameLoadRequest(frame->coreFrame(), ResourceRequest(URL(URL(), url)))); + frame->coreFrame()->loader().load(FrameLoadRequest(frame->coreFrame(), ResourceRequest(URL(URL(), url)), ShouldOpenExternalURLsPolicy::ShouldNotAllow)); +} + +#if !PLATFORM(COCOA) +void WebPage::platformDidReceiveLoadParameters(const LoadParameters& loadParameters) +{ } +#endif -void WebPage::loadRequest(const ResourceRequest& request, const SandboxExtension::Handle& sandboxExtensionHandle, IPC::MessageDecoder& decoder) +void WebPage::loadRequest(const LoadParameters& loadParameters) { SendStopResponsivenessTimer stopper(this); - RefPtr<API::Object> userData; - InjectedBundleUserMessageDecoder userMessageDecoder(userData); - if (!decoder.decode(userMessageDecoder)) - return; + m_pendingNavigationID = loadParameters.navigationID; - m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), sandboxExtensionHandle); + m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), loadParameters.sandboxExtensionHandle); // Let the InjectedBundle know we are about to start the load, passing the user data from the UIProcess // to all the client to set up any needed state. - m_loaderClient.willLoadURLRequest(this, request, userData.get()); + m_loaderClient.willLoadURLRequest(this, loadParameters.request, WebProcess::singleton().transformHandlesToObjects(loadParameters.userData.object()).get()); + + platformDidReceiveLoadParameters(loadParameters); // Initate the load in WebCore. - m_mainFrame->coreFrame()->loader().load(FrameLoadRequest(m_mainFrame->coreFrame(), request)); + FrameLoadRequest frameLoadRequest(m_mainFrame->coreFrame(), loadParameters.request, ShouldOpenExternalURLsPolicy::ShouldNotAllow); + ShouldOpenExternalURLsPolicy externalURLsPolicy = static_cast<ShouldOpenExternalURLsPolicy>(loadParameters.shouldOpenExternalURLsPolicy); + frameLoadRequest.setShouldOpenExternalURLsPolicy(externalURLsPolicy); + + corePage()->userInputBridge().loadRequest(frameLoadRequest); + + ASSERT(!m_pendingNavigationID); } -void WebPage::loadDataImpl(PassRefPtr<SharedBuffer> sharedBuffer, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& unreachableURL, IPC::MessageDecoder& decoder) +void WebPage::loadDataImpl(uint64_t navigationID, PassRefPtr<SharedBuffer> sharedBuffer, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& unreachableURL, const UserData& userData) { SendStopResponsivenessTimer stopper(this); - RefPtr<API::Object> userData; - InjectedBundleUserMessageDecoder userMessageDecoder(userData); - if (!decoder.decode(userMessageDecoder)) - return; + m_pendingNavigationID = navigationID; ResourceRequest request(baseURL); - SubstituteData substituteData(sharedBuffer, MIMEType, encodingName, unreachableURL); + ResourceResponse response(URL(), MIMEType, sharedBuffer->size(), encodingName); + SubstituteData substituteData(sharedBuffer, unreachableURL, response, SubstituteData::SessionHistoryVisibility::Hidden); // Let the InjectedBundle know we are about to start the load, passing the user data from the UIProcess // to all the client to set up any needed state. - m_loaderClient.willLoadDataRequest(this, request, const_cast<SharedBuffer*>(substituteData.content()), substituteData.mimeType(), substituteData.textEncoding(), substituteData.failingURL(), userData.get()); + m_loaderClient.willLoadDataRequest(this, request, const_cast<SharedBuffer*>(substituteData.content()), substituteData.mimeType(), substituteData.textEncoding(), substituteData.failingURL(), WebProcess::singleton().transformHandlesToObjects(userData.object()).get()); // Initate the load in WebCore. - m_mainFrame->coreFrame()->loader().load(FrameLoadRequest(m_mainFrame->coreFrame(), request, substituteData)); + m_mainFrame->coreFrame()->loader().load(FrameLoadRequest(m_mainFrame->coreFrame(), request, ShouldOpenExternalURLsPolicy::ShouldNotAllow, substituteData)); } -void WebPage::loadString(const String& htmlString, const String& MIMEType, const URL& baseURL, const URL& unreachableURL, IPC::MessageDecoder& decoder) +void WebPage::loadStringImpl(uint64_t navigationID, const String& htmlString, const String& MIMEType, const URL& baseURL, const URL& unreachableURL, const UserData& userData) { if (!htmlString.isNull() && htmlString.is8Bit()) { RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(htmlString.characters8()), htmlString.length() * sizeof(LChar)); - loadDataImpl(sharedBuffer, MIMEType, ASCIILiteral("latin1"), baseURL, unreachableURL, decoder); + loadDataImpl(navigationID, sharedBuffer, MIMEType, ASCIILiteral("latin1"), baseURL, unreachableURL, userData); } else { RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(htmlString.characters16()), htmlString.length() * sizeof(UChar)); - loadDataImpl(sharedBuffer, MIMEType, ASCIILiteral("utf-16"), baseURL, unreachableURL, decoder); + loadDataImpl(navigationID, sharedBuffer, MIMEType, ASCIILiteral("utf-16"), baseURL, unreachableURL, userData); } } -void WebPage::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encodingName, const String& baseURLString, IPC::MessageDecoder& decoder) +void WebPage::loadData(const LoadParameters& loadParameters) { - RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(data.data()), data.size()); - URL baseURL = baseURLString.isEmpty() ? blankURL() : URL(URL(), baseURLString); - loadDataImpl(sharedBuffer, MIMEType, encodingName, baseURL, URL(), decoder); -} + platformDidReceiveLoadParameters(loadParameters); -void WebPage::loadHTMLString(const String& htmlString, const String& baseURLString, IPC::MessageDecoder& decoder) -{ - URL baseURL = baseURLString.isEmpty() ? blankURL() : URL(URL(), baseURLString); - loadString(htmlString, ASCIILiteral("text/html"), baseURL, URL(), decoder); + RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(loadParameters.data.data()), loadParameters.data.size()); + URL baseURL = loadParameters.baseURLString.isEmpty() ? blankURL() : URL(URL(), loadParameters.baseURLString); + loadDataImpl(loadParameters.navigationID, sharedBuffer, loadParameters.MIMEType, loadParameters.encodingName, baseURL, URL(), loadParameters.userData); } -void WebPage::loadAlternateHTMLString(const String& htmlString, const String& baseURLString, const String& unreachableURLString, IPC::MessageDecoder& decoder) +void WebPage::loadString(const LoadParameters& loadParameters) { - URL baseURL = baseURLString.isEmpty() ? blankURL() : URL(URL(), baseURLString); - URL unreachableURL = unreachableURLString.isEmpty() ? URL() : URL(URL(), unreachableURLString); - loadString(htmlString, ASCIILiteral("text/html"), baseURL, unreachableURL, decoder); + platformDidReceiveLoadParameters(loadParameters); + + URL baseURL = loadParameters.baseURLString.isEmpty() ? blankURL() : URL(URL(), loadParameters.baseURLString); + loadStringImpl(loadParameters.navigationID, loadParameters.string, loadParameters.MIMEType, baseURL, URL(), loadParameters.userData); } -void WebPage::loadPlainTextString(const String& string, IPC::MessageDecoder& decoder) +void WebPage::loadAlternateHTMLString(const LoadParameters& loadParameters) { - loadString(string, ASCIILiteral("text/plain"), blankURL(), URL(), decoder); + platformDidReceiveLoadParameters(loadParameters); + + URL baseURL = loadParameters.baseURLString.isEmpty() ? blankURL() : URL(URL(), loadParameters.baseURLString); + URL unreachableURL = loadParameters.unreachableURLString.isEmpty() ? URL() : URL(URL(), loadParameters.unreachableURLString); + URL provisionalLoadErrorURL = loadParameters.provisionalLoadErrorURLString.isEmpty() ? URL() : URL(URL(), loadParameters.provisionalLoadErrorURLString); + m_mainFrame->coreFrame()->loader().setProvisionalLoadErrorBeingHandledURL(provisionalLoadErrorURL); + loadStringImpl(0, loadParameters.string, ASCIILiteral("text/html"), baseURL, unreachableURL, loadParameters.userData); + m_mainFrame->coreFrame()->loader().setProvisionalLoadErrorBeingHandledURL({ }); } -void WebPage::loadWebArchiveData(const IPC::DataReference& webArchiveData, IPC::MessageDecoder& decoder) +void WebPage::navigateToPDFLinkWithSimulatedClick(const String& url, IntPoint documentPoint, IntPoint screenPoint) { - RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(webArchiveData.data()), webArchiveData.size() * sizeof(uint8_t)); - loadDataImpl(sharedBuffer, ASCIILiteral("application/x-webarchive"), ASCIILiteral("utf-16"), blankURL(), URL(), decoder); + Frame* mainFrame = m_mainFrame->coreFrame(); + Document* mainFrameDocument = mainFrame->document(); + if (!mainFrameDocument) + return; + + const int singleClick = 1; + RefPtr<MouseEvent> mouseEvent = MouseEvent::create(eventNames().clickEvent, true, true, currentTime(), nullptr, singleClick, screenPoint.x(), screenPoint.y(), documentPoint.x(), documentPoint.y(), +#if ENABLE(POINTER_LOCK) + 0, 0, +#endif + false, false, false, false, 0, nullptr, 0, WebCore::NoTap, nullptr); + + mainFrame->loader().urlSelected(mainFrameDocument->completeURL(url), emptyString(), mouseEvent.get(), LockHistory::No, LockBackForwardList::No, ShouldSendReferrer::MaybeSendReferrer, ShouldOpenExternalURLsPolicy::ShouldNotAllow); } void WebPage::stopLoadingFrame(uint64_t frameID) { - WebFrame* frame = WebProcess::shared().webFrame(frameID); + WebFrame* frame = WebProcess::singleton().webFrame(frameID); if (!frame) return; - frame->coreFrame()->loader().stopForUserCancel(); + corePage()->userInputBridge().stopLoadingFrame(frame->coreFrame()); } void WebPage::stopLoading() { SendStopResponsivenessTimer stopper(this); - m_mainFrame->coreFrame()->loader().stopForUserCancel(); + corePage()->userInputBridge().stopLoadingFrame(m_mainFrame->coreFrame()); +} + +bool WebPage::defersLoading() const +{ + return m_page->defersLoading(); } void WebPage::setDefersLoading(bool defersLoading) @@ -1009,15 +1280,18 @@ void WebPage::setDefersLoading(bool defersLoading) m_page->setDefersLoading(defersLoading); } -void WebPage::reload(bool reloadFromOrigin, const SandboxExtension::Handle& sandboxExtensionHandle) +void WebPage::reload(uint64_t navigationID, bool reloadFromOrigin, bool contentBlockersEnabled, const SandboxExtension::Handle& sandboxExtensionHandle) { SendStopResponsivenessTimer stopper(this); + ASSERT(!m_mainFrame->coreFrame()->loader().frameHasLoaded() || !m_pendingNavigationID); + m_pendingNavigationID = navigationID; + m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), sandboxExtensionHandle); - m_mainFrame->coreFrame()->loader().reload(reloadFromOrigin); + corePage()->userInputBridge().reloadFrame(m_mainFrame->coreFrame(), reloadFromOrigin, contentBlockersEnabled); } -void WebPage::goForward(uint64_t backForwardItemID) +void WebPage::goForward(uint64_t navigationID, uint64_t backForwardItemID) { SendStopResponsivenessTimer stopper(this); @@ -1026,10 +1300,13 @@ void WebPage::goForward(uint64_t backForwardItemID) if (!item) return; - m_page->goToItem(item, FrameLoadTypeForward); + ASSERT(!m_pendingNavigationID); + m_pendingNavigationID = navigationID; + + m_page->goToItem(*item, FrameLoadType::Forward); } -void WebPage::goBack(uint64_t backForwardItemID) +void WebPage::goBack(uint64_t navigationID, uint64_t backForwardItemID) { SendStopResponsivenessTimer stopper(this); @@ -1038,10 +1315,13 @@ void WebPage::goBack(uint64_t backForwardItemID) if (!item) return; - m_page->goToItem(item, FrameLoadTypeBack); + ASSERT(!m_pendingNavigationID); + m_pendingNavigationID = navigationID; + + m_page->goToItem(*item, FrameLoadType::Back); } -void WebPage::goToBackForwardItem(uint64_t backForwardItemID) +void WebPage::goToBackForwardItem(uint64_t navigationID, uint64_t backForwardItemID) { SendStopResponsivenessTimer stopper(this); @@ -1050,7 +1330,10 @@ void WebPage::goToBackForwardItem(uint64_t backForwardItemID) if (!item) return; - m_page->goToItem(item, FrameLoadTypeIndexedBackForward); + ASSERT(!m_pendingNavigationID); + m_pendingNavigationID = navigationID; + + m_page->goToItem(*item, FrameLoadType::IndexedBackForward); } void WebPage::tryRestoreScrollPosition() @@ -1066,7 +1349,7 @@ void WebPage::layoutIfNeeded() WebPage* WebPage::fromCorePage(Page* page) { - return static_cast<WebChromeClient&>(page->chrome().client()).page(); + return &static_cast<WebChromeClient&>(page->chrome().client()).page(); } void WebPage::setSize(const WebCore::IntSize& viewSize) @@ -1074,29 +1357,22 @@ void WebPage::setSize(const WebCore::IntSize& viewSize) if (m_viewSize == viewSize) return; + m_viewSize = viewSize; FrameView* view = m_page->mainFrame().view(); view->resize(viewSize); m_drawingArea->setNeedsDisplay(); - - m_viewSize = viewSize; -#if USE(TILED_BACKING_STORE) +#if USE(COORDINATED_GRAPHICS) if (view->useFixedLayout()) - sendViewportAttributesChanged(); + sendViewportAttributesChanged(m_page->viewportArguments()); #endif } -#if USE(TILED_BACKING_STORE) -void WebPage::setFixedVisibleContentRect(const IntRect& rect) -{ - ASSERT(m_useFixedLayout); - - m_page->mainFrame().view()->setFixedVisibleContentRect(rect); -} - -void WebPage::sendViewportAttributesChanged() +#if USE(COORDINATED_GRAPHICS) +void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArguments) { - ASSERT(m_useFixedLayout); + FrameView* view = m_page->mainFrame().view(); + ASSERT(view && view->useFixedLayout()); // Viewport properties have no impact on zero sized fixed viewports. if (m_viewSize.isEmpty()) @@ -1111,9 +1387,7 @@ void WebPage::sendViewportAttributesChanged() int deviceWidth = (settings.deviceWidth() > 0) ? settings.deviceWidth() : m_viewSize.width(); int deviceHeight = (settings.deviceHeight() > 0) ? settings.deviceHeight() : m_viewSize.height(); - ViewportAttributes attr = computeViewportAttributes(m_page->viewportArguments(), minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize); - - FrameView* view = m_page->mainFrame().view(); + ViewportAttributes attr = computeViewportAttributes(viewportArguments, minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize); // If no layout was done yet set contentFixedOrigin to (0,0). IntPoint contentFixedOrigin = view->didFirstLayout() ? view->fixedVisibleContentRect().location() : IntPoint(); @@ -1129,14 +1403,18 @@ void WebPage::sendViewportAttributesChanged() #endif contentFixedSize.scale(1 / attr.initialScale); - setFixedVisibleContentRect(IntRect(contentFixedOrigin, roundedIntSize(contentFixedSize))); + view->setFixedVisibleContentRect(IntRect(contentFixedOrigin, roundedIntSize(contentFixedSize))); attr.initialScale = m_page->viewportArguments().zoom; // Resets auto (-1) if no value was set by user. // This also takes care of the relayout. setFixedLayoutSize(roundedIntSize(attr.layoutSize)); +#if USE(COORDINATED_GRAPHICS_THREADED) + m_drawingArea->didChangeViewportAttributes(WTFMove(attr)); +#else send(Messages::WebPageProxy::DidChangeViewportProperties(attr)); +#endif } #endif @@ -1144,8 +1422,8 @@ void WebPage::scrollMainFrameIfNotAtMaxScrollPosition(const IntSize& scrollOffse { FrameView* frameView = m_page->mainFrame().view(); - IntPoint scrollPosition = frameView->scrollPosition(); - IntPoint maximumScrollPosition = frameView->maximumScrollPosition(); + ScrollPosition scrollPosition = frameView->scrollPosition(); + ScrollPosition maximumScrollPosition = frameView->maximumScrollPosition(); // If the current scroll position in a direction is the max scroll position // we don't want to scroll at all. @@ -1166,20 +1444,18 @@ void WebPage::drawRect(GraphicsContext& graphicsContext, const IntRect& rect) GraphicsContextStateSaver stateSaver(graphicsContext); graphicsContext.clip(rect); - m_mainFrame->coreFrame()->view()->paint(&graphicsContext, rect); -} - -void WebPage::drawPageOverlay(PageOverlay* pageOverlay, GraphicsContext& graphicsContext, const IntRect& rect) -{ - ASSERT(pageOverlay); - - GraphicsContextStateSaver stateSaver(graphicsContext); - graphicsContext.clip(rect); - pageOverlay->drawRect(graphicsContext, rect); + m_mainFrame->coreFrame()->view()->paint(graphicsContext, rect); } double WebPage::textZoomFactor() const { + PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); + if (pluginView && pluginView->requiresUnifiedScaleFactor()) { + if (pluginView->handlesPageScaleFactor()) + return pluginView->pageScaleFactor(); + return pageScaleFactor(); + } + Frame* frame = m_mainFrame->coreFrame(); if (!frame) return 1; @@ -1189,8 +1465,13 @@ double WebPage::textZoomFactor() const void WebPage::setTextZoomFactor(double zoomFactor) { PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); - if (pluginView && pluginView->handlesPageScaleFactor()) + if (pluginView && pluginView->requiresUnifiedScaleFactor()) { + if (pluginView->handlesPageScaleFactor()) + pluginView->setPageScaleFactor(zoomFactor, IntPoint()); + else + scalePage(zoomFactor, IntPoint()); return; + } Frame* frame = m_mainFrame->coreFrame(); if (!frame) @@ -1201,8 +1482,11 @@ void WebPage::setTextZoomFactor(double zoomFactor) double WebPage::pageZoomFactor() const { PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); - if (pluginView && pluginView->handlesPageScaleFactor()) - return pluginView->pageScaleFactor(); + if (pluginView && pluginView->requiresUnifiedScaleFactor()) { + if (pluginView->handlesPageScaleFactor()) + return pluginView->pageScaleFactor(); + return pageScaleFactor(); + } Frame* frame = m_mainFrame->coreFrame(); if (!frame) @@ -1213,8 +1497,11 @@ double WebPage::pageZoomFactor() const void WebPage::setPageZoomFactor(double zoomFactor) { PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); - if (pluginView && pluginView->handlesPageScaleFactor()) { - pluginView->setPageScaleFactor(zoomFactor, IntPoint()); + if (pluginView && pluginView->requiresUnifiedScaleFactor()) { + if (pluginView->handlesPageScaleFactor()) + pluginView->setPageScaleFactor(zoomFactor, IntPoint()); + else + scalePage(zoomFactor, IntPoint()); return; } @@ -1227,8 +1514,11 @@ void WebPage::setPageZoomFactor(double zoomFactor) void WebPage::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor) { PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); - if (pluginView && pluginView->handlesPageScaleFactor()) { - pluginView->setPageScaleFactor(pageZoomFactor, IntPoint()); + if (pluginView && pluginView->requiresUnifiedScaleFactor()) { + if (pluginView->handlesPageScaleFactor()) + pluginView->setPageScaleFactor(pageZoomFactor, IntPoint()); + else + scalePage(pageZoomFactor, IntPoint()); return; } @@ -1238,39 +1528,102 @@ void WebPage::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFa return frame->setPageAndTextZoomFactors(static_cast<float>(pageZoomFactor), static_cast<float>(textZoomFactor)); } -void WebPage::windowScreenDidChange(uint64_t displayID) +void WebPage::windowScreenDidChange(uint32_t displayID) { m_page->chrome().windowScreenDidChange(static_cast<PlatformDisplayID>(displayID)); } void WebPage::scalePage(double scale, const IntPoint& origin) { + double totalScale = scale * viewScaleFactor(); + bool willChangeScaleFactor = totalScale != totalScaleFactor(); + +#if PLATFORM(IOS) + if (willChangeScaleFactor) { + if (!m_inDynamicSizeUpdate) + m_dynamicSizeUpdateHistory.clear(); + m_scaleWasSetByUIProcess = false; + } +#endif PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); if (pluginView && pluginView->handlesPageScaleFactor()) { - pluginView->setPageScaleFactor(scale, origin); + // If the main-frame plugin wants to handle the page scale factor, make sure to reset WebCore's page scale. + // Otherwise, we can end up with an immutable but non-1 page scale applied by WebCore on top of whatever the plugin does. + if (m_page->pageScaleFactor() != 1) { + m_page->setPageScaleFactor(1, origin); + for (auto* pluginView : m_pluginViews) + pluginView->pageScaleFactorDidChange(); + } + + pluginView->setPageScaleFactor(totalScale, origin); return; } - m_page->setPageScaleFactor(scale, origin); + m_page->setPageScaleFactor(totalScale, origin); + + // We can't early return before setPageScaleFactor because the origin might be different. + if (!willChangeScaleFactor) + return; for (auto* pluginView : m_pluginViews) pluginView->pageScaleFactorDidChange(); - if (m_drawingArea->layerTreeHost()) - m_drawingArea->layerTreeHost()->deviceOrPageScaleFactorChanged(); +#if USE(COORDINATED_GRAPHICS) || USE(TEXTURE_MAPPER) + m_drawingArea->deviceOrPageScaleFactorChanged(); +#endif send(Messages::WebPageProxy::PageScaleFactorDidChange(scale)); } -double WebPage::pageScaleFactor() const +void WebPage::scalePageInViewCoordinates(double scale, IntPoint centerInViewCoordinates) +{ + double totalScale = scale * viewScaleFactor(); + if (totalScale == totalScaleFactor()) + return; + + IntPoint scrollPositionAtNewScale = mainFrameView()->rootViewToContents(-centerInViewCoordinates); + double scaleRatio = scale / pageScaleFactor(); + scrollPositionAtNewScale.scale(scaleRatio); + scalePage(scale, scrollPositionAtNewScale); +} + +double WebPage::totalScaleFactor() const { PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()); if (pluginView && pluginView->handlesPageScaleFactor()) return pluginView->pageScaleFactor(); - + return m_page->pageScaleFactor(); } +double WebPage::pageScaleFactor() const +{ + return totalScaleFactor() / viewScaleFactor(); +} + +double WebPage::viewScaleFactor() const +{ + return m_page->viewScaleFactor(); +} + +void WebPage::scaleView(double scale) +{ + if (viewScaleFactor() == scale) + return; + + float pageScale = pageScaleFactor(); + + IntPoint scrollPositionAtNewScale; + if (FrameView* mainFrameView = m_page->mainFrame().view()) { + double scaleRatio = scale / viewScaleFactor(); + scrollPositionAtNewScale = mainFrameView->scrollPosition(); + scrollPositionAtNewScale.scale(scaleRatio); + } + + m_page->setViewScaleFactor(scale); + scalePage(pageScale, scrollPositionAtNewScale); +} + void WebPage::setDeviceScaleFactor(float scaleFactor) { if (scaleFactor == m_page->deviceScaleFactor()) @@ -1279,7 +1632,7 @@ void WebPage::setDeviceScaleFactor(float scaleFactor) m_page->setDeviceScaleFactor(scaleFactor); // Tell all our plug-in views that the device scale factor changed. -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) for (auto* pluginView : m_pluginViews) pluginView->setDeviceScaleFactor(scaleFactor); @@ -1292,8 +1645,9 @@ void WebPage::setDeviceScaleFactor(float scaleFactor) m_findController.deviceScaleFactorDidChange(); } - if (m_drawingArea->layerTreeHost()) - m_drawingArea->layerTreeHost()->deviceOrPageScaleFactorChanged(); +#if USE(COORDINATED_GRAPHICS) || USE(TEXTURE_MAPPER) + m_drawingArea->deviceOrPageScaleFactorChanged(); +#endif } float WebPage::deviceScaleFactor() const @@ -1301,6 +1655,11 @@ float WebPage::deviceScaleFactor() const return m_page->deviceScaleFactor(); } +void WebPage::accessibilitySettingsDidChange() +{ + m_page->accessibilitySettingsDidChange(); +} + void WebPage::setUseFixedLayout(bool fixed) { // Do not overwrite current settings if initially setting it to false. @@ -1308,7 +1667,9 @@ void WebPage::setUseFixedLayout(bool fixed) return; m_useFixedLayout = fixed; +#if !PLATFORM(IOS) m_page->settings().setFixedElementsLayoutRelativeToFrame(fixed); +#endif #if USE(COORDINATED_GRAPHICS) m_page->settings().setAcceleratedCompositingForFixedPositionEnabled(fixed); m_page->settings().setFixedPositionCreatesStackingContext(fixed); @@ -1316,7 +1677,7 @@ void WebPage::setUseFixedLayout(bool fixed) m_page->settings().setScrollingCoordinatorEnabled(fixed); #endif -#if USE(TILED_BACKING_STORE) && ENABLE(SMOOTH_SCROLLING) +#if USE(COORDINATED_GRAPHICS) && ENABLE(SMOOTH_SCROLLING) // Delegated scrolling will be enabled when the FrameView is created if fixed layout is enabled. // Ensure we don't do animated scrolling in the WebProcess in that case. m_page->settings().setScrollAnimatorEnabled(!fixed); @@ -1326,25 +1687,57 @@ void WebPage::setUseFixedLayout(bool fixed) if (!view) return; -#if USE(TILED_BACKING_STORE) +#if USE(COORDINATED_GRAPHICS) view->setDelegatesScrolling(fixed); view->setPaintsEntireContents(fixed); #endif view->setUseFixedLayout(fixed); if (!fixed) setFixedLayoutSize(IntSize()); + + send(Messages::WebPageProxy::UseFixedLayoutDidChange(fixed)); } -void WebPage::setFixedLayoutSize(const IntSize& size) +bool WebPage::setFixedLayoutSize(const IntSize& size) { FrameView* view = mainFrameView(); if (!view || view->fixedLayoutSize() == size) - return; + return false; view->setFixedLayoutSize(size); - // Do not force it until the first layout, this would then become our first layout prematurely. - if (view->didFirstLayout()) - view->forceLayout(); + + send(Messages::WebPageProxy::FixedLayoutSizeDidChange(size)); + return true; +} + +IntSize WebPage::fixedLayoutSize() const +{ + FrameView* view = mainFrameView(); + if (!view) + return IntSize(); + return view->fixedLayoutSize(); +} + +void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArguments) +{ +#if PLATFORM(IOS) + if (m_viewportConfiguration.setViewportArguments(viewportArguments)) + viewportConfigurationChanged(); +#endif + +#if USE(COORDINATED_GRAPHICS) + FrameView* view = m_page->mainFrame().view(); + if (view && view->useFixedLayout()) + sendViewportAttributesChanged(viewportArguments); +#if USE(COORDINATED_GRAPHICS_THREADED) + else + m_drawingArea->didChangeViewportAttributes(ViewportAttributes()); +#endif +#endif + +#if !PLATFORM(IOS) && !USE(COORDINATED_GRAPHICS) + UNUSED_PARAM(viewportArguments); +#endif } void WebPage::listenForLayoutMilestones(uint32_t milestones) @@ -1358,6 +1751,16 @@ void WebPage::setSuppressScrollbarAnimations(bool suppressAnimations) { m_page->setShouldSuppressScrollbarAnimations(suppressAnimations); } + +void WebPage::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding) +{ + m_page->setVerticalScrollElasticity(enableVerticalRubberBanding ? ScrollElasticityAllowed : ScrollElasticityNone); +} + +void WebPage::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding) +{ + m_page->setHorizontalScrollElasticity(enableHorizontalRubberBanding ? ScrollElasticityAllowed : ScrollElasticityNone); +} void WebPage::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage) { @@ -1393,55 +1796,24 @@ void WebPage::setGapBetweenPages(double gap) m_page->setPagination(pagination); } -void WebPage::postInjectedBundleMessage(const String& messageName, IPC::MessageDecoder& decoder) +void WebPage::setPaginationLineGridEnabled(bool lineGridEnabled) { - InjectedBundle* injectedBundle = WebProcess::shared().injectedBundle(); - if (!injectedBundle) - return; - - RefPtr<API::Object> messageBody; - InjectedBundleUserMessageDecoder messageBodyDecoder(messageBody); - if (!decoder.decode(messageBodyDecoder)) - return; - - injectedBundle->didReceiveMessageToPage(this, messageName, messageBody.get()); + m_page->setPaginationLineGridEnabled(lineGridEnabled); } -void WebPage::installPageOverlay(PassRefPtr<PageOverlay> pageOverlay, bool shouldFadeIn) +void WebPage::postInjectedBundleMessage(const String& messageName, const UserData& userData) { - RefPtr<PageOverlay> overlay = pageOverlay; - - if (m_pageOverlays.contains(overlay.get())) - return; - - m_pageOverlays.append(overlay); - overlay->setPage(this); - - if (shouldFadeIn) - overlay->startFadeInAnimation(); - - m_drawingArea->didInstallPageOverlay(overlay.get()); -} - -void WebPage::uninstallPageOverlay(PageOverlay* pageOverlay, bool shouldFadeOut) -{ - size_t existingOverlayIndex = m_pageOverlays.find(pageOverlay); - if (existingOverlayIndex == notFound) - return; - - if (shouldFadeOut) { - pageOverlay->startFadeOutAnimation(); + auto& webProcess = WebProcess::singleton(); + InjectedBundle* injectedBundle = webProcess.injectedBundle(); + if (!injectedBundle) return; - } - pageOverlay->setPage(0); - m_pageOverlays.remove(existingOverlayIndex); - - m_drawingArea->didUninstallPageOverlay(pageOverlay); + injectedBundle->didReceiveMessageToPage(this, messageName, webProcess.transformHandlesToObjects(userData.object()).get()); } #if !PLATFORM(IOS) -void WebPage::setHeaderPageBanner(PassRefPtr<PageBanner> pageBanner) + +void WebPage::setHeaderPageBanner(PageBanner* pageBanner) { if (m_headerBanner) m_headerBanner->detachFromPage(); @@ -1457,7 +1829,7 @@ PageBanner* WebPage::headerPageBanner() return m_headerBanner.get(); } -void WebPage::setFooterPageBanner(PassRefPtr<PageBanner> pageBanner) +void WebPage::setFooterPageBanner(PageBanner* pageBanner) { if (m_footerBanner) m_footerBanner->detachFromPage(); @@ -1488,32 +1860,93 @@ void WebPage::showPageBanners() if (m_footerBanner) m_footerBanner->showIfHidden(); } + +void WebPage::setHeaderBannerHeightForTesting(int height) +{ +#if ENABLE(RUBBER_BANDING) + corePage()->addHeaderWithHeight(height); +#endif +} + +void WebPage::setFooterBannerHeightForTesting(int height) +{ +#if ENABLE(RUBBER_BANDING) + corePage()->addFooterWithHeight(height); +#endif +} + #endif // !PLATFORM(IOS) -PassRefPtr<WebImage> WebPage::scaledSnapshotWithOptions(const IntRect& rect, double scaleFactor, SnapshotOptions options) +void WebPage::takeSnapshot(IntRect snapshotRect, IntSize bitmapSize, uint32_t options, uint64_t callbackID) +{ + SnapshotOptions snapshotOptions = static_cast<SnapshotOptions>(options); + snapshotOptions |= SnapshotOptionsShareable; + + RefPtr<WebImage> image = snapshotAtSize(snapshotRect, bitmapSize, snapshotOptions); + + ShareableBitmap::Handle handle; + if (image) + image->bitmap().createHandle(handle, SharedMemory::Protection::ReadOnly); + + send(Messages::WebPageProxy::ImageCallback(handle, callbackID)); +} + +PassRefPtr<WebImage> WebPage::scaledSnapshotWithOptions(const IntRect& rect, double additionalScaleFactor, SnapshotOptions options) +{ + IntRect snapshotRect = rect; + IntSize bitmapSize = snapshotRect.size(); + if (options & SnapshotOptionsPrinting) { + ASSERT(additionalScaleFactor == 1); + Frame* coreFrame = m_mainFrame->coreFrame(); + if (!coreFrame) + return nullptr; + bitmapSize.setHeight(PrintContext::numberOfPages(*coreFrame, bitmapSize) * (bitmapSize.height() + 1) - 1); + } else { + double scaleFactor = additionalScaleFactor; + if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) + scaleFactor *= corePage()->deviceScaleFactor(); + bitmapSize.scale(scaleFactor); + } + + return snapshotAtSize(rect, bitmapSize, options); +} + +PassRefPtr<WebImage> WebPage::snapshotAtSize(const IntRect& rect, const IntSize& bitmapSize, SnapshotOptions options) { Frame* coreFrame = m_mainFrame->coreFrame(); if (!coreFrame) - return 0; + return nullptr; FrameView* frameView = coreFrame->view(); if (!frameView) - return 0; + return nullptr; - IntSize bitmapSize = rect.size(); - float combinedScaleFactor = scaleFactor * corePage()->deviceScaleFactor(); - bitmapSize.scale(combinedScaleFactor); + IntRect snapshotRect = rect; + float horizontalScaleFactor = static_cast<float>(bitmapSize.width()) / rect.width(); + float verticalScaleFactor = static_cast<float>(bitmapSize.height()) / rect.height(); + float scaleFactor = std::max(horizontalScaleFactor, verticalScaleFactor); - RefPtr<WebImage> snapshot = WebImage::create(bitmapSize, snapshotOptionsToImageOptions(options)); - if (!snapshot->bitmap()) - return 0; + auto snapshot = WebImage::create(bitmapSize, snapshotOptionsToImageOptions(options)); + + auto graphicsContext = snapshot->bitmap().createGraphicsContext(); + + if (options & SnapshotOptionsPrinting) { + PrintContext::spoolAllPagesWithBoundaries(*coreFrame, *graphicsContext, snapshotRect.size()); + return snapshot; + } - auto graphicsContext = snapshot->bitmap()->createGraphicsContext(); + Color documentBackgroundColor = frameView->documentBackgroundColor(); + Color backgroundColor = (coreFrame->settings().backgroundShouldExtendBeyondPage() && documentBackgroundColor.isValid()) ? documentBackgroundColor : frameView->baseBackgroundColor(); + graphicsContext->fillRect(IntRect(IntPoint(), bitmapSize), backgroundColor); - graphicsContext->clearRect(IntRect(IntPoint(), bitmapSize)); + if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) { + double deviceScaleFactor = corePage()->deviceScaleFactor(); + graphicsContext->applyDeviceScaleFactor(deviceScaleFactor); + scaleFactor /= deviceScaleFactor; + } - graphicsContext->applyDeviceScaleFactor(combinedScaleFactor); - graphicsContext->translate(-rect.x(), -rect.y()); + graphicsContext->scale(scaleFactor); + graphicsContext->translate(-snapshotRect.x(), -snapshotRect.y()); FrameView::SelectionInSnapshot shouldPaintSelection = FrameView::IncludeSelection; if (options & SnapshotOptionsExcludeSelectionHighlighting) @@ -1523,28 +1956,94 @@ PassRefPtr<WebImage> WebPage::scaledSnapshotWithOptions(const IntRect& rect, dou if (options & SnapshotOptionsInViewCoordinates) coordinateSpace = FrameView::ViewCoordinates; - frameView->paintContentsForSnapshot(graphicsContext.get(), rect, shouldPaintSelection, coordinateSpace); + frameView->paintContentsForSnapshot(*graphicsContext, snapshotRect, shouldPaintSelection, coordinateSpace); if (options & SnapshotOptionsPaintSelectionRectangle) { - FloatRect selectionRectangle = m_mainFrame->coreFrame()->selection().bounds(); - graphicsContext->setStrokeColor(Color(0xFF, 0, 0), ColorSpaceDeviceRGB); + FloatRect selectionRectangle = m_mainFrame->coreFrame()->selection().selectionBounds(); + graphicsContext->setStrokeColor(Color(0xFF, 0, 0)); graphicsContext->strokeRect(selectionRectangle, 1); } + + return snapshot; +} + +PassRefPtr<WebImage> WebPage::snapshotNode(WebCore::Node& node, SnapshotOptions options, unsigned maximumPixelCount) +{ + Frame* coreFrame = m_mainFrame->coreFrame(); + if (!coreFrame) + return nullptr; - return snapshot.release(); + FrameView* frameView = coreFrame->view(); + if (!frameView) + return nullptr; + + if (!node.renderer()) + return nullptr; + + LayoutRect topLevelRect; + IntRect snapshotRect = snappedIntRect(node.renderer()->paintingRootRect(topLevelRect)); + if (snapshotRect.isEmpty()) + return nullptr; + + double scaleFactor = 1; + IntSize snapshotSize = snapshotRect.size(); + unsigned maximumHeight = maximumPixelCount / snapshotSize.width(); + if (maximumHeight < static_cast<unsigned>(snapshotSize.height())) { + scaleFactor = static_cast<double>(maximumHeight) / snapshotSize.height(); + snapshotSize = IntSize(snapshotSize.width() * scaleFactor, maximumHeight); + } + + auto snapshot = WebImage::create(snapshotSize, snapshotOptionsToImageOptions(options)); + + auto graphicsContext = snapshot->bitmap().createGraphicsContext(); + + if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) { + double deviceScaleFactor = corePage()->deviceScaleFactor(); + graphicsContext->applyDeviceScaleFactor(deviceScaleFactor); + scaleFactor /= deviceScaleFactor; + } + + graphicsContext->scale(scaleFactor); + graphicsContext->translate(-snapshotRect.x(), -snapshotRect.y()); + + Color savedBackgroundColor = frameView->baseBackgroundColor(); + frameView->setBaseBackgroundColor(Color::transparent); + frameView->setNodeToDraw(&node); + + frameView->paintContentsForSnapshot(*graphicsContext, snapshotRect, FrameView::ExcludeSelection, FrameView::DocumentCoordinates); + + frameView->setBaseBackgroundColor(savedBackgroundColor); + frameView->setNodeToDraw(nullptr); + + return snapshot; } void WebPage::pageDidScroll() { - m_uiClient.pageDidScroll(this); +#if PLATFORM(IOS) + if (!m_inDynamicSizeUpdate) + m_dynamicSizeUpdateHistory.clear(); +#endif + m_uiClient->pageDidScroll(this); + + m_pageScrolledHysteresis.impulse(); send(Messages::WebPageProxy::PageDidScroll()); } -#if USE(TILED_BACKING_STORE) +void WebPage::pageStoppedScrolling() +{ + // Maintain the current history item's scroll position up-to-date. + if (Frame* frame = m_mainFrame->coreFrame()) + frame->loader().history().saveScrollPositionAndViewStateToItem(frame->loader().history().currentItem()); +} + +#if USE(COORDINATED_GRAPHICS) void WebPage::pageDidRequestScroll(const IntPoint& point) { - send(Messages::WebPageProxy::PageDidRequestScroll(point)); +#if USE(COORDINATED_GRAPHICS_THREADED) + drawingArea()->scroll(IntRect(point, IntSize()), IntSize()); +#endif } #endif @@ -1559,14 +2058,16 @@ WebContextMenu* WebPage::contextMenu() WebContextMenu* WebPage::contextMenuAtPointInWindow(const IntPoint& point) { corePage()->contextMenuController().clearContextMenu(); - + // Simulate a mouse click to generate the correct menu. - PlatformMouseEvent mouseEvent(point, point, RightButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime()); - bool handled = corePage()->mainFrame().eventHandler().sendContextMenuEvent(mouseEvent); - if (!handled) - return 0; + PlatformMouseEvent mousePressEvent(point, point, RightButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime(), WebCore::ForceAtClick, WebCore::NoTap); + corePage()->userInputBridge().handleMousePressEvent(mousePressEvent); + bool handled = corePage()->userInputBridge().handleContextMenuEvent(mousePressEvent, &corePage()->mainFrame()); + auto* menu = handled ? contextMenu() : nullptr; + PlatformMouseEvent mouseReleaseEvent(point, point, RightButton, PlatformEvent::MouseReleased, 1, false, false, false, false, currentTime(), WebCore::ForceAtClick, WebCore::NoTap); + corePage()->userInputBridge().handleMouseReleaseEvent(mouseReleaseEvent); - return contextMenu(); + return menu; } #endif @@ -1582,6 +2083,75 @@ const WebEvent* WebPage::currentEvent() return g_currentEvent; } +void WebPage::setLayerTreeStateIsFrozen(bool frozen) +{ + auto* drawingArea = this->drawingArea(); + if (!drawingArea) + return; + + drawingArea->setLayerTreeStateIsFrozen(frozen); +} + +void WebPage::callVolatilityCompletionHandlers() +{ + auto completionHandlers = WTFMove(m_markLayersAsVolatileCompletionHandlers); + for (auto& completionHandler : completionHandlers) + completionHandler(); +} + +void WebPage::layerVolatilityTimerFired() +{ + auto newInterval = 2 * m_layerVolatilityTimer.repeatIntervalMS(); + bool didSucceed = markLayersVolatileImmediatelyIfPossible(); + if (didSucceed || newInterval > maximumLayerVolatilityTimerInterval) { + m_layerVolatilityTimer.stop(); + RELEASE_LOG_IF_ALLOWED("%p - WebPage - Attempted to mark layers as volatile, success? %d", this, didSucceed); + callVolatilityCompletionHandlers(); + return; + } + + RELEASE_LOG_ERROR_IF_ALLOWED("%p - WebPage - Failed to mark all layers as volatile, will retry in %lld ms", this, static_cast<long long>(newInterval.count())); + m_layerVolatilityTimer.startRepeating(newInterval); +} + +bool WebPage::markLayersVolatileImmediatelyIfPossible() +{ + return !drawingArea() || drawingArea()->markLayersVolatileImmediatelyIfPossible(); +} + +void WebPage::markLayersVolatile(std::function<void ()> completionHandler) +{ + RELEASE_LOG_IF_ALLOWED("%p - WebPage::markLayersVolatile()", this); + + if (m_layerVolatilityTimer.isActive()) + m_layerVolatilityTimer.stop(); + + if (completionHandler) + m_markLayersAsVolatileCompletionHandlers.append(WTFMove(completionHandler)); + + bool didSucceed = markLayersVolatileImmediatelyIfPossible(); + if (didSucceed || m_isSuspendedUnderLock) { + if (didSucceed) + RELEASE_LOG_IF_ALLOWED("%p - WebPage - Successfully marked layers as volatile", this); + else { + // If we get suspended when locking the screen, it is expected that some IOSurfaces cannot be marked as purgeable so we do not keep retrying. + RELEASE_LOG_IF_ALLOWED("%p - WebPage - Did what we could to mark IOSurfaces as purgeable after locking the screen", this); + } + callVolatilityCompletionHandlers(); + return; + } + + RELEASE_LOG_IF_ALLOWED("%p - Failed to mark all layers as volatile, will retry in %lld ms", this, initialLayerVolatilityTimerInterval.count()); + m_layerVolatilityTimer.startRepeating(initialLayerVolatilityTimerInterval); +} + +void WebPage::cancelMarkLayersVolatile() +{ + RELEASE_LOG_IF_ALLOWED("%p - WebPage::cancelMarkLayersVolatile()", this); + m_layerVolatilityTimer.stop(); + m_markLayersAsVolatileCompletionHandlers.clear(); +} + class CurrentEvent { public: explicit CurrentEvent(const WebEvent& event) @@ -1602,16 +2172,11 @@ private: #if ENABLE(CONTEXT_MENUS) static bool isContextClick(const PlatformMouseEvent& event) { - if (event.button() == WebCore::RightButton) - return true; - -#if PLATFORM(MAC) - // FIXME: this really should be about OSX-style UI, not about the Mac port - if (event.button() == WebCore::LeftButton && event.ctrlKey()) - return true; +#if PLATFORM(COCOA) + return WebEventFactory::shouldBeHandledAsContextClick(event); +#else + return event.button() == WebCore::RightButton; #endif - - return false; } static bool handleContextMenuEvent(const PlatformMouseEvent& platformMouseEvent, WebPage* page) @@ -1622,13 +2187,23 @@ static bool handleContextMenuEvent(const PlatformMouseEvent& platformMouseEvent, Frame* frame = &page->corePage()->mainFrame(); if (result.innerNonSharedNode()) frame = result.innerNonSharedNode()->document().frame(); - - bool handled = frame->eventHandler().sendContextMenuEvent(platformMouseEvent); + + bool handled = page->corePage()->userInputBridge().handleContextMenuEvent(platformMouseEvent, frame); if (handled) page->contextMenu()->show(); return handled; } + +void WebPage::contextMenuForKeyEvent() +{ + corePage()->contextMenuController().clearContextMenu(); + + Frame& frame = m_page->focusController().focusedOrMainFrame(); + bool handled = frame.eventHandler().sendContextMenuEventForKey(); + if (handled) + contextMenu()->show(); +} #endif static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, bool onlyUpdateScrollbars) @@ -1646,7 +2221,7 @@ static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, boo page->corePage()->contextMenuController().clearContextMenu(); #endif - bool handled = frame.eventHandler().handleMousePressEvent(platformMouseEvent); + bool handled = page->corePage()->userInputBridge().handleMousePressEvent(platformMouseEvent); #if ENABLE(CONTEXT_MENUS) if (isContextClick(platformMouseEvent)) handled = handleContextMenuEvent(platformMouseEvent, page); @@ -1654,12 +2229,18 @@ static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, boo return handled; } case PlatformEvent::MouseReleased: - return frame.eventHandler().handleMouseReleaseEvent(platformMouseEvent); + return page->corePage()->userInputBridge().handleMouseReleaseEvent(platformMouseEvent); case PlatformEvent::MouseMoved: if (onlyUpdateScrollbars) - return frame.eventHandler().passMouseMovedEventToScrollbars(platformMouseEvent); - return frame.eventHandler().mouseMoved(platformMouseEvent); + return page->corePage()->userInputBridge().handleMouseMoveOnScrollbarEvent(platformMouseEvent); + return page->corePage()->userInputBridge().handleMouseMoveEvent(platformMouseEvent); + + case PlatformEvent::MouseForceChanged: + case PlatformEvent::MouseForceDown: + case PlatformEvent::MouseForceUp: + return page->corePage()->userInputBridge().handleMouseForceEvent(platformMouseEvent); + default: ASSERT_NOT_REACHED(); return false; @@ -1668,21 +2249,28 @@ static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, boo void WebPage::mouseEvent(const WebMouseEvent& mouseEvent) { + SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true }; + + m_userActivityHysteresis.impulse(); + + bool shouldHandleEvent = true; + #if ENABLE(CONTEXT_MENUS) // Don't try to handle any pending mouse events if a context menu is showing. - if (m_isShowingContextMenu) { + if (m_isShowingContextMenu) + shouldHandleEvent = false; +#endif +#if ENABLE(DRAG_SUPPORT) + if (m_isStartingDrag) + shouldHandleEvent = false; +#endif + + if (!shouldHandleEvent) { send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), false)); return; } -#endif + bool handled = false; - if (m_pageOverlays.size()) { - // Let the page overlay handle the event. - PageOverlayList::reverse_iterator end = m_pageOverlays.rend(); - for (PageOverlayList::reverse_iterator it = m_pageOverlays.rbegin(); it != end; ++it) - if ((handled = (*it)->mouseEvent(mouseEvent))) - break; - } #if !PLATFORM(IOS) if (!handled && m_headerBanner) @@ -1691,7 +2279,7 @@ void WebPage::mouseEvent(const WebMouseEvent& mouseEvent) handled = m_footerBanner->mouseEvent(mouseEvent); #endif // !PLATFORM(IOS) - if (!handled && canHandleUserEvents()) { + if (!handled) { CurrentEvent currentEvent(mouseEvent); // We need to do a full, normal hit test during this mouse event if the page is active or if a mouse @@ -1706,36 +2294,6 @@ void WebPage::mouseEvent(const WebMouseEvent& mouseEvent) send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), handled)); } -void WebPage::mouseEventSyncForTesting(const WebMouseEvent& mouseEvent, bool& handled) -{ - handled = false; - - if (m_pageOverlays.size()) { - PageOverlayList::reverse_iterator end = m_pageOverlays.rend(); - for (PageOverlayList::reverse_iterator it = m_pageOverlays.rbegin(); it != end; ++it) - if ((handled = (*it)->mouseEvent(mouseEvent))) - break; - } -#if !PLATFORM(IOS) - if (!handled && m_headerBanner) - handled = m_headerBanner->mouseEvent(mouseEvent); - if (!handled && m_footerBanner) - handled = m_footerBanner->mouseEvent(mouseEvent); -#endif // !PLATFORM(IOS) - - if (!handled) { - CurrentEvent currentEvent(mouseEvent); - - // We need to do a full, normal hit test during this mouse event if the page is active or if a mouse - // button is currently pressed. It is possible that neither of those things will be true since on - // Lion when legacy scrollbars are enabled, WebKit receives mouse events all the time. If it is one - // of those cases where the page is not active and the mouse is not pressed, then we can fire a more - // efficient scrollbars-only version of the event. - bool onlyUpdateScrollbars = !(m_page->focusController().isActive() || (mouseEvent.button() != WebMouseEvent::NoButton)); - handled = handleMouseEvent(mouseEvent, this, onlyUpdateScrollbars); - } -} - static bool handleWheelEvent(const WebWheelEvent& wheelEvent, Page* page) { Frame& frame = page->mainFrame(); @@ -1743,26 +2301,18 @@ static bool handleWheelEvent(const WebWheelEvent& wheelEvent, Page* page) return false; PlatformWheelEvent platformWheelEvent = platform(wheelEvent); - return frame.eventHandler().handleWheelEvent(platformWheelEvent); + return page->userInputBridge().handleWheelEvent(platformWheelEvent); } void WebPage::wheelEvent(const WebWheelEvent& wheelEvent) { - bool handled = false; + m_userActivityHysteresis.impulse(); - if (canHandleUserEvents()) { - CurrentEvent currentEvent(wheelEvent); - - handled = handleWheelEvent(wheelEvent, m_page.get()); - } - send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(wheelEvent.type()), handled)); -} - -void WebPage::wheelEventSyncForTesting(const WebWheelEvent& wheelEvent, bool& handled) -{ CurrentEvent currentEvent(wheelEvent); - handled = handleWheelEvent(wheelEvent, m_page.get()); + bool handled = handleWheelEvent(wheelEvent, m_page.get()); + + send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(wheelEvent.type()), handled)); } static bool handleKeyEvent(const WebKeyboardEvent& keyboardEvent, Page* page) @@ -1771,61 +2321,24 @@ static bool handleKeyEvent(const WebKeyboardEvent& keyboardEvent, Page* page) return false; if (keyboardEvent.type() == WebEvent::Char && keyboardEvent.isSystemKey()) - return page->focusController().focusedOrMainFrame().eventHandler().handleAccessKey(platform(keyboardEvent)); - return page->focusController().focusedOrMainFrame().eventHandler().keyEvent(platform(keyboardEvent)); + return page->userInputBridge().handleAccessKeyEvent(platform(keyboardEvent)); + return page->userInputBridge().handleKeyEvent(platform(keyboardEvent)); } void WebPage::keyEvent(const WebKeyboardEvent& keyboardEvent) { - bool handled = false; + SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true }; - if (canHandleUserEvents()) { - CurrentEvent currentEvent(keyboardEvent); + m_userActivityHysteresis.impulse(); - handled = handleKeyEvent(keyboardEvent, m_page.get()); - // FIXME: Platform default behaviors should be performed during normal DOM event dispatch (in most cases, in default keydown event handler). - if (!handled) - handled = performDefaultBehaviorForKeyEvent(keyboardEvent); - } - send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(keyboardEvent.type()), handled)); -} - -void WebPage::keyEventSyncForTesting(const WebKeyboardEvent& keyboardEvent, bool& handled) -{ CurrentEvent currentEvent(keyboardEvent); - Frame& frame = m_page->focusController().focusedOrMainFrame(); - frame.document()->updateStyleIfNeeded(); - - handled = handleKeyEvent(keyboardEvent, m_page.get()); + bool handled = handleKeyEvent(keyboardEvent, m_page.get()); + // FIXME: Platform default behaviors should be performed during normal DOM event dispatch (in most cases, in default keydown event handler). if (!handled) handled = performDefaultBehaviorForKeyEvent(keyboardEvent); -} - -WKTypeRef WebPage::pageOverlayCopyAccessibilityAttributeValue(WKStringRef attribute, WKTypeRef parameter) -{ - if (!m_pageOverlays.size()) - return 0; - PageOverlayList::reverse_iterator end = m_pageOverlays.rend(); - for (PageOverlayList::reverse_iterator it = m_pageOverlays.rbegin(); it != end; ++it) { - WKTypeRef value = (*it)->copyAccessibilityAttributeValue(attribute, parameter); - if (value) - return value; - } - return 0; -} -WKArrayRef WebPage::pageOverlayCopyAccessibilityAttributesNames(bool parameterizedNames) -{ - if (!m_pageOverlays.size()) - return 0; - PageOverlayList::reverse_iterator end = m_pageOverlays.rend(); - for (PageOverlayList::reverse_iterator it = m_pageOverlays.rbegin(); it != end; ++it) { - WKArrayRef value = (*it)->copyAccessibilityAttributeNames(parameterizedNames); - if (value) - return value; - } - return 0; + send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(keyboardEvent.type()), handled)); } void WebPage::validateCommand(const String& commandName, uint64_t callbackID) @@ -1844,39 +2357,23 @@ void WebPage::validateCommand(const String& commandName, uint64_t callbackID) send(Messages::WebPageProxy::ValidateCommandCallback(commandName, isEnabled, state, callbackID)); } -void WebPage::executeEditCommand(const String& commandName) +void WebPage::executeEditCommand(const String& commandName, const String& argument) { - executeEditingCommand(commandName, String()); + executeEditingCommand(commandName, argument); } -uint64_t WebPage::restoreSession(const SessionState& sessionState) +void WebPage::restoreSessionInternal(const Vector<BackForwardListItemState>& itemStates, WasRestoredByAPIRequest restoredByAPIRequest) { - const BackForwardListItemVector& list = sessionState.list(); - size_t size = list.size(); - uint64_t currentItemID = 0; - for (size_t i = 0; i < size; ++i) { - WebBackForwardListItem* webItem = list[i].get(); - DecoderAdapter decoder(webItem->backForwardData().data(), webItem->backForwardData().size()); - - RefPtr<HistoryItem> item = HistoryItem::decodeBackForwardTree(webItem->url(), webItem->title(), webItem->originalURL(), decoder); - if (!item) { - LOG_ERROR("Failed to decode a HistoryItem from session state data."); - return 0; - } - - if (i == sessionState.currentIndex()) - currentItemID = webItem->itemID(); - - WebBackForwardListProxy::addItemFromUIProcess(list[i]->itemID(), item.release()); - } - ASSERT(currentItemID); - return currentItemID; + for (const auto& itemState : itemStates) { + auto historyItem = toHistoryItem(itemState.pageState); + historyItem->setWasRestoredFromSession(restoredByAPIRequest == WasRestoredByAPIRequest::Yes); + static_cast<WebBackForwardListProxy*>(corePage()->backForward().client())->addItemFromUIProcess(itemState.identifier, WTFMove(historyItem), m_pageID); + } } -void WebPage::restoreSessionAndNavigateToCurrentItem(const SessionState& sessionState) +void WebPage::restoreSession(const Vector<BackForwardListItemState>& itemStates) { - if (uint64_t currentItemID = restoreSession(sessionState)) - goToBackForwardItem(currentItemID); + restoreSessionInternal(itemStates, WasRestoredByAPIRequest::Yes); } #if ENABLE(TOUCH_EVENTS) @@ -1887,34 +2384,62 @@ static bool handleTouchEvent(const WebTouchEvent& touchEvent, Page* page) return page->mainFrame().eventHandler().handleTouchEvent(platform(touchEvent)); } +#endif + +#if ENABLE(IOS_TOUCH_EVENTS) +void WebPage::dispatchTouchEvent(const WebTouchEvent& touchEvent, bool& handled) +{ + SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true }; + + m_lastInteractionLocation = touchEvent.position(); + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(touchEvent, m_page.get()); +} + +void WebPage::touchEventSync(const WebTouchEvent& touchEvent, bool& handled) +{ + EventDispatcher::TouchEventQueue queuedEvents; + WebProcess::singleton().eventDispatcher().getQueuedTouchEventsForPage(*this, queuedEvents); + dispatchAsynchronousTouchEvents(queuedEvents); + dispatchTouchEvent(touchEvent, handled); +} +#elif ENABLE(TOUCH_EVENTS) void WebPage::touchEvent(const WebTouchEvent& touchEvent) { - bool handled = false; + CurrentEvent currentEvent(touchEvent); - if (canHandleUserEvents()) { - CurrentEvent currentEvent(touchEvent); + bool handled = handleTouchEvent(touchEvent, m_page.get()); - handled = handleTouchEvent(touchEvent, m_page.get()); - } send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(touchEvent.type()), handled)); } +#endif -void WebPage::touchEventSyncForTesting(const WebTouchEvent& touchEvent, bool& handled) +#if ENABLE(MAC_GESTURE_EVENTS) +static bool handleGestureEvent(const WebGestureEvent& event, Page* page) { - CurrentEvent currentEvent(touchEvent); - handled = handleTouchEvent(touchEvent, m_page.get()); + if (!page->mainFrame().view()) + return false; + + return page->mainFrame().eventHandler().handleGestureEvent(platform(event)); +} + +void WebPage::gestureEvent(const WebGestureEvent& gestureEvent) +{ + CurrentEvent currentEvent(gestureEvent); + bool handled = handleGestureEvent(gestureEvent, m_page.get()); + send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(gestureEvent.type()), handled)); } #endif bool WebPage::scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity) { - return page->focusController().focusedOrMainFrame().eventHandler().scrollRecursively(direction, granularity); + return page->userInputBridge().scrollRecursively(direction, granularity); } bool WebPage::logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity) { - return page->focusController().focusedOrMainFrame().eventHandler().logicalScrollRecursively(direction, granularity); + return page->userInputBridge().logicalScrollRecursively(direction, granularity); } bool WebPage::scrollBy(uint32_t scrollDirection, uint32_t scrollGranularity) @@ -1925,21 +2450,39 @@ bool WebPage::scrollBy(uint32_t scrollDirection, uint32_t scrollGranularity) void WebPage::centerSelectionInVisibleArea() { Frame& frame = m_page->focusController().focusedOrMainFrame(); - frame.selection().revealSelection(ScrollAlignment::alignCenterAlways); + frame.selection().revealSelection(SelectionRevealMode::Reveal, ScrollAlignment::alignCenterAlways); m_findController.showFindIndicatorInSelection(); } -void WebPage::setActive(bool isActive) +bool WebPage::isControlledByAutomation() const +{ + return m_page->isControlledByAutomation(); +} + +void WebPage::setControlledByAutomation(bool controlled) +{ + m_page->setControlledByAutomation(controlled); +} + +void WebPage::insertNewlineInQuotedContent() { - m_page->focusController().setActive(isActive); + Frame& frame = m_page->focusController().focusedOrMainFrame(); + if (frame.selection().isNone()) + return; + frame.editor().insertParagraphSeparatorInQuotedContent(); } -void WebPage::setViewIsVisible(bool isVisible) +#if ENABLE(REMOTE_INSPECTOR) +void WebPage::setAllowsRemoteInspection(bool allow) { - corePage()->focusController().setContentIsVisible(isVisible); + m_page->setRemoteInspectionAllowed(allow); +} - m_page->setIsVisible(m_viewState & ViewState::IsVisible, false); +void WebPage::setRemoteInspectionNameOverride(const String& name) +{ + m_page->setRemoteInspectionNameOverride(name); } +#endif void WebPage::setDrawsBackground(bool drawsBackground) { @@ -1957,21 +2500,26 @@ void WebPage::setDrawsBackground(bool drawsBackground) m_drawingArea->setNeedsDisplay(); } -void WebPage::setDrawsTransparentBackground(bool drawsTransparentBackground) +#if HAVE(COREANIMATION_FENCES) +void WebPage::setTopContentInsetFenced(float contentInset, IPC::Attachment fencePort) { - if (m_drawsTransparentBackground == drawsTransparentBackground) - return; + m_drawingArea->addFence(MachSendRight::create(fencePort.port())); - m_drawsTransparentBackground = drawsTransparentBackground; + setTopContentInset(contentInset); - Color backgroundColor = drawsTransparentBackground ? Color::transparent : Color::white; - for (Frame* coreFrame = m_mainFrame->coreFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) { - if (FrameView* view = coreFrame->view()) - view->setBaseBackgroundColor(backgroundColor); - } + mach_port_deallocate(mach_task_self(), fencePort.port()); +} +#endif - m_drawingArea->pageBackgroundTransparencyChanged(); - m_drawingArea->setNeedsDisplay(); +void WebPage::setTopContentInset(float contentInset) +{ + if (contentInset == m_page->topContentInset()) + return; + + m_page->setTopContentInset(contentInset); + + for (auto* pluginView : m_pluginViews) + pluginView->topContentInsetDidChange(); } void WebPage::viewWillStartLiveResize() @@ -1996,41 +2544,27 @@ void WebPage::viewWillEndLiveResize() view->willEndLiveResize(); } -void WebPage::setFocused(bool isFocused) -{ - m_page->focusController().setFocused(isFocused); -} - -void WebPage::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& event) +void WebPage::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& event, uint64_t callbackID) { if (!m_page) return; + SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true }; + Frame& frame = m_page->focusController().focusedOrMainFrame(); frame.document()->setFocusedElement(0); if (isKeyboardEventValid && event.type() == WebEvent::KeyDown) { PlatformKeyboardEvent platformEvent(platform(event)); platformEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown); - m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, KeyboardEvent::create(platformEvent, frame.document()->defaultView()).get()); - return; - } - - m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, 0); -} + m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, &KeyboardEvent::create(platformEvent, frame.document()->defaultView()).get()); -void WebPage::setWindowResizerSize(const IntSize& windowResizerSize) -{ - if (m_windowResizerSize == windowResizerSize) + send(Messages::WebPageProxy::VoidCallback(callbackID)); return; - - m_windowResizerSize = windowResizerSize; - - for (Frame* coreFrame = m_mainFrame->coreFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) { - FrameView* view = coreFrame->view(); - if (view) - view->windowResizerRectChanged(); } + + m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, nullptr); + send(Messages::WebPageProxy::VoidCallback(callbackID)); } void WebPage::setCanStartMediaTimerFired() @@ -2039,32 +2573,17 @@ void WebPage::setCanStartMediaTimerFired() m_page->setCanStartMedia(true); } -#if !PLATFORM(MAC) || PLATFORM(IOS) -void WebPage::didUpdateViewStateTimerFired() -{ - send(Messages::WebPageProxy::DidUpdateViewState()); -} -#endif - -inline bool WebPage::canHandleUserEvents() const +void WebPage::updateIsInWindow(bool isInitialState) { -#if USE(TILED_BACKING_STORE) - // Should apply only if the area was frozen by didStartPageTransition(). - return !m_drawingArea->layerTreeStateIsFrozen(); -#endif - return true; -} + bool isInWindow = m_activityState & WebCore::ActivityState::IsInWindow; -void WebPage::setIsInWindow(bool isInWindow) -{ - bool pageWasInWindow = m_page->isInWindow(); - if (!isInWindow) { m_setCanStartMediaTimer.stop(); m_page->setCanStartMedia(false); - if (pageWasInWindow) - WebProcess::shared().pageWillLeaveWindow(m_pageID); + // The WebProcess does not yet know about this page; no need to tell it we're leaving the window. + if (!isInitialState) + WebProcess::singleton().pageWillLeaveWindow(m_pageID); } else { // Defer the call to Page::setCanStartMedia() since it ends up sending a synchronous message to the UI process // in order to get plug-in connections, and the UI process will be waiting for the Web process to update the backing @@ -2072,53 +2591,34 @@ void WebPage::setIsInWindow(bool isInWindow) if (m_mayStartMediaWhenInWindow) m_setCanStartMediaTimer.startOneShot(0); - if (!pageWasInWindow) - WebProcess::shared().pageDidEnterWindow(m_pageID); + WebProcess::singleton().pageDidEnterWindow(m_pageID); } - m_page->setIsInWindow(isInWindow); - if (isInWindow) layoutIfNeeded(); } -void WebPage::setViewState(ViewState::Flags viewState, bool wantsDidUpdateViewState) +void WebPage::setActivityState(ActivityState::Flags activityState, bool wantsDidUpdateActivityState, const Vector<uint64_t>& callbackIDs) { - setViewStateInternal(viewState, false); + ActivityState::Flags changed = m_activityState ^ activityState; + m_activityState = activityState; - if (wantsDidUpdateViewState) - m_sendDidUpdateViewStateTimer.startOneShot(0); -} + if (changed) + updateThrottleState(); -void WebPage::setViewStateInternal(ViewState::Flags viewState, bool isInitialState) -{ - ViewState::Flags changed = m_viewState ^ viewState; - m_viewState = viewState; - - m_drawingArea->viewStateDidChange(changed); + m_page->setActivityState(activityState); + for (auto* pluginView : m_pluginViews) + pluginView->activityStateDidChange(changed); - // We want to make sure to update the active state while hidden, so if the view is hidden then update the active state - // early (in case it becomes visible), and if the view was visible then update active state later (in case it hides). - if (changed & ViewState::IsFocused) - setFocused(viewState & ViewState::IsFocused); - if (changed & ViewState::WindowIsActive && !(m_viewState & ViewState::IsVisible)) - setActive(viewState & ViewState::WindowIsActive); - if (changed & ViewState::IsVisible) - setViewIsVisible(viewState & ViewState::IsVisible); - if (changed & ViewState::WindowIsActive && m_viewState & ViewState::IsVisible) - setActive(viewState & ViewState::WindowIsActive); - if (changed & ViewState::IsInWindow) - setIsInWindow(viewState & ViewState::IsInWindow); - if (changed & ViewState::IsVisuallyIdle) - setIsVisuallyIdle(viewState & ViewState::IsVisuallyIdle); + m_drawingArea->activityStateDidChange(changed, wantsDidUpdateActivityState, callbackIDs); - for (auto* pluginView : m_pluginViews) - pluginView->viewStateDidChange(changed); + if (changed & ActivityState::IsInWindow) + updateIsInWindow(); } -void WebPage::setLayerHostingMode(unsigned layerHostingMode) +void WebPage::setLayerHostingMode(LayerHostingMode layerHostingMode) { - m_layerHostingMode = static_cast<LayerHostingMode>(layerHostingMode); + m_layerHostingMode = layerHostingMode; m_drawingArea->setLayerHostingMode(m_layerHostingMode); @@ -2126,36 +2626,47 @@ void WebPage::setLayerHostingMode(unsigned layerHostingMode) pluginView->setLayerHostingMode(m_layerHostingMode); } -uint64_t WebPage::sessionID() const +void WebPage::setSessionID(SessionID sessionID) { - if (m_sessionID) - return m_sessionID; - - return m_page->settings().privateBrowsingEnabled() ? SessionTracker::legacyPrivateSessionID : SessionTracker::defaultSessionID; + if (sessionID.isEphemeral()) + WebProcess::singleton().ensurePrivateBrowsingSession(sessionID); + m_page->setSessionID(sessionID); } -void WebPage::didReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction, uint64_t downloadID) +void WebPage::didReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction, uint64_t navigationID, DownloadID downloadID) { - WebFrame* frame = WebProcess::shared().webFrame(frameID); + WebFrame* frame = WebProcess::singleton().webFrame(frameID); if (!frame) return; - frame->didReceivePolicyDecision(listenerID, static_cast<PolicyAction>(policyAction), downloadID); + frame->didReceivePolicyDecision(listenerID, static_cast<PolicyAction>(policyAction), navigationID, downloadID); } void WebPage::didStartPageTransition() { m_drawingArea->setLayerTreeStateIsFrozen(true); + +#if PLATFORM(MAC) + bool hasPreviouslyFocusedDueToUserInteraction = m_hasEverFocusedElementDueToUserInteractionSincePageTransition; +#endif + m_hasEverFocusedElementDueToUserInteractionSincePageTransition = false; + m_isAssistingNodeDueToUserInteraction = false; + m_lastEditorStateWasContentEditable = EditorStateIsContentEditable::Unset; +#if PLATFORM(MAC) + if (hasPreviouslyFocusedDueToUserInteraction) + send(Messages::WebPageProxy::SetHasHadSelectionChangesFromUserInteraction(m_hasEverFocusedElementDueToUserInteractionSincePageTransition)); + if (m_needsHiddenContentEditableQuirk) { + m_needsHiddenContentEditableQuirk = false; + send(Messages::WebPageProxy::SetNeedsHiddenContentEditableQuirk(m_needsHiddenContentEditableQuirk)); + } + if (m_needsPlainTextQuirk) { + m_needsPlainTextQuirk = false; + send(Messages::WebPageProxy::SetNeedsPlainTextQuirk(m_needsPlainTextQuirk)); + } +#endif } void WebPage::didCompletePageTransition() { -#if USE(TILED_BACKING_STORE) - if (m_mainFrame->coreFrame()->view()->delegatesScrolling()) - // Wait until the UI process sent us the visible rect it wants rendered. - send(Messages::WebPageProxy::PageTransitionViewportReady()); - else -#endif - m_drawingArea->setLayerTreeStateIsFrozen(false); } @@ -2164,19 +2675,29 @@ void WebPage::show() send(Messages::WebPageProxy::ShowPage()); } -void WebPage::setUserAgent(const String& userAgent) +String WebPage::userAgent(const URL& webCoreURL) const { - m_userAgent = userAgent; + return userAgent(nullptr, webCoreURL); } -String WebPage::userAgent(const URL& url) const +String WebPage::userAgent(WebFrame* frame, const URL& webcoreURL) const { - String userAgent = platformUserAgent(url); + if (frame && m_loaderClient.client().userAgentForURL) { + API::String* apiString = m_loaderClient.userAgentForURL(frame, API::URL::create(webcoreURL).ptr()); + if (apiString) + return apiString->string(); + } + + String userAgent = platformUserAgent(webcoreURL); if (!userAgent.isEmpty()) return userAgent; - return m_userAgent; } + +void WebPage::setUserAgent(const String& userAgent) +{ + m_userAgent = userAgent; +} void WebPage::suspendActiveDOMObjectsAndAnimations() { @@ -2188,38 +2709,39 @@ void WebPage::resumeActiveDOMObjectsAndAnimations() m_page->resumeActiveDOMObjectsAndAnimations(); } -IntPoint WebPage::screenToWindow(const IntPoint& point) +IntPoint WebPage::screenToRootView(const IntPoint& point) { IntPoint windowPoint; - sendSync(Messages::WebPageProxy::ScreenToWindow(point), Messages::WebPageProxy::ScreenToWindow::Reply(windowPoint)); + sendSync(Messages::WebPageProxy::ScreenToRootView(point), Messages::WebPageProxy::ScreenToRootView::Reply(windowPoint)); return windowPoint; } -IntRect WebPage::windowToScreen(const IntRect& rect) +IntRect WebPage::rootViewToScreen(const IntRect& rect) { IntRect screenRect; - sendSync(Messages::WebPageProxy::WindowToScreen(rect), Messages::WebPageProxy::WindowToScreen::Reply(screenRect)); + sendSync(Messages::WebPageProxy::RootViewToScreen(rect), Messages::WebPageProxy::RootViewToScreen::Reply(screenRect)); return screenRect; } - -IntRect WebPage::windowResizerRect() const + +#if PLATFORM(IOS) +IntPoint WebPage::accessibilityScreenToRootView(const IntPoint& point) { - if (m_windowResizerSize.isEmpty()) - return IntRect(); - - IntSize frameViewSize; - if (Frame* coreFrame = m_mainFrame->coreFrame()) { - if (FrameView* view = coreFrame->view()) - frameViewSize = view->size(); - } + IntPoint windowPoint; + sendSync(Messages::WebPageProxy::AccessibilityScreenToRootView(point), Messages::WebPageProxy::AccessibilityScreenToRootView::Reply(windowPoint)); + return windowPoint; +} - return IntRect(frameViewSize.width() - m_windowResizerSize.width(), frameViewSize.height() - m_windowResizerSize.height(), - m_windowResizerSize.width(), m_windowResizerSize.height()); +IntRect WebPage::rootViewToAccessibilityScreen(const IntRect& rect) +{ + IntRect screenRect; + sendSync(Messages::WebPageProxy::RootViewToAccessibilityScreen(rect), Messages::WebPageProxy::RootViewToAccessibilityScreen::Reply(screenRect)); + return screenRect; } +#endif KeyboardUIMode WebPage::keyboardUIMode() { - bool fullKeyboardAccessEnabled = WebProcess::shared().fullKeyboardAccessEnabled(); + bool fullKeyboardAccessEnabled = WebProcess::singleton().fullKeyboardAccessEnabled(); return static_cast<KeyboardUIMode>((fullKeyboardAccessEnabled ? KeyboardAccessFull : KeyboardAccessDefault) | (m_tabToLinks ? KeyboardAccessTabsToLinks : 0)); } @@ -2228,18 +2750,20 @@ void WebPage::runJavaScriptInMainFrame(const String& script, uint64_t callbackID // NOTE: We need to be careful when running scripts that the objects we depend on don't // disappear during script execution. - // Retain the SerializedScriptValue at this level so it (and the internal data) lives - // long enough for the DataReference to be encoded by the sent message. RefPtr<SerializedScriptValue> serializedResultValue; - IPC::DataReference dataReference; - - JSLockHolder lock(JSDOMWindow::commonVM()); - if (JSValue resultValue = m_mainFrame->coreFrame()->script().executeScript(script, true).jsValue()) { - if ((serializedResultValue = SerializedScriptValue::create(m_mainFrame->jsContext(), toRef(m_mainFrame->coreFrame()->script().globalObject(mainThreadNormalWorld())->globalExec(), resultValue), 0))) - dataReference = serializedResultValue->data(); + JSLockHolder lock(commonVM()); + bool hadException = true; + ExceptionDetails details; + if (JSValue resultValue = m_mainFrame->coreFrame()->script().executeScript(script, true, &details)) { + hadException = false; + serializedResultValue = SerializedScriptValue::create(m_mainFrame->jsContext(), + toRef(m_mainFrame->coreFrame()->script().globalObject(mainThreadNormalWorld())->globalExec(), resultValue), nullptr); } - send(Messages::WebPageProxy::ScriptValueCallback(dataReference, callbackID)); + IPC::DataReference dataReference; + if (serializedResultValue) + dataReference = serializedResultValue->data(); + send(Messages::WebPageProxy::ScriptValueCallback(dataReference, hadException, details, callbackID)); } void WebPage::getContentsAsString(uint64_t callbackID) @@ -2249,17 +2773,14 @@ void WebPage::getContentsAsString(uint64_t callbackID) } #if ENABLE(MHTML) -void WebPage::getContentsAsMHTMLData(uint64_t callbackID, bool useBinaryEncoding) +void WebPage::getContentsAsMHTMLData(uint64_t callbackID) { - IPC::DataReference dataReference; - - RefPtr<SharedBuffer> buffer = useBinaryEncoding - ? MHTMLArchive::generateMHTMLDataUsingBinaryEncoding(m_page.get()) - : MHTMLArchive::generateMHTMLData(m_page.get()); + RefPtr<SharedBuffer> buffer = MHTMLArchive::generateMHTMLData(m_page.get()); + // FIXME: Use SharedBufferDataReference. + IPC::DataReference dataReference; if (buffer) dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()); - send(Messages::WebPageProxy::DataCallback(dataReference, callbackID)); } #endif @@ -2282,35 +2803,33 @@ static Frame* frameWithSelection(Page* page) void WebPage::getSelectionAsWebArchiveData(uint64_t callbackID) { - IPC::DataReference dataReference; - -#if PLATFORM(MAC) - RefPtr<LegacyWebArchive> archive; +#if PLATFORM(COCOA) RetainPtr<CFDataRef> data; + if (Frame* frame = frameWithSelection(m_page.get())) + data = LegacyWebArchive::createFromSelection(frame)->rawDataRepresentation(); +#endif - Frame* frame = frameWithSelection(m_page.get()); - if (frame) { - archive = LegacyWebArchive::createFromSelection(frame); - data = archive->rawDataRepresentation(); + IPC::DataReference dataReference; +#if PLATFORM(COCOA) + if (data) dataReference = IPC::DataReference(CFDataGetBytePtr(data.get()), CFDataGetLength(data.get())); - } #endif - send(Messages::WebPageProxy::DataCallback(dataReference, callbackID)); } void WebPage::getSelectionOrContentsAsString(uint64_t callbackID) { - String resultString = m_mainFrame->selectionAsString(); + WebFrame* focusedOrMainFrame = WebFrame::fromCoreFrame(m_page->focusController().focusedOrMainFrame()); + String resultString = focusedOrMainFrame->selectionAsString(); if (resultString.isEmpty()) - resultString = m_mainFrame->contentsAsString(); + resultString = focusedOrMainFrame->contentsAsString(); send(Messages::WebPageProxy::StringCallback(resultString, callbackID)); } void WebPage::getSourceForFrame(uint64_t frameID, uint64_t callbackID) { String resultString; - if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) + if (WebFrame* frame = WebProcess::singleton().webFrame(frameID)) resultString = frame->source(); send(Messages::WebPageProxy::StringCallback(resultString, callbackID)); @@ -2318,74 +2837,70 @@ void WebPage::getSourceForFrame(uint64_t frameID, uint64_t callbackID) void WebPage::getMainResourceDataOfFrame(uint64_t frameID, uint64_t callbackID) { - IPC::DataReference dataReference; - - RefPtr<ResourceBuffer> buffer; - RefPtr<SharedBuffer> pdfResource; - if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) { - if (PluginView* pluginView = pluginViewForFrame(frame->coreFrame())) { - if ((pdfResource = pluginView->liveResourceData())) - dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(pdfResource->data()), pdfResource->size()); - } - - if (dataReference.isEmpty()) { - if (DocumentLoader* loader = frame->coreFrame()->loader().documentLoader()) { - if ((buffer = loader->mainResourceData())) - dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()); - } + RefPtr<SharedBuffer> buffer; + if (WebFrame* frame = WebProcess::singleton().webFrame(frameID)) { + if (PluginView* pluginView = pluginViewForFrame(frame->coreFrame())) + buffer = pluginView->liveResourceData(); + if (!buffer) { + if (DocumentLoader* loader = frame->coreFrame()->loader().documentLoader()) + buffer = loader->mainResourceData(); } } + // FIXME: Use SharedBufferDataReference. + IPC::DataReference dataReference; + if (buffer) + dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()); send(Messages::WebPageProxy::DataCallback(dataReference, callbackID)); } -static PassRefPtr<SharedBuffer> resourceDataForFrame(Frame* frame, const URL& resourceURL) +static RefPtr<SharedBuffer> resourceDataForFrame(Frame* frame, const URL& resourceURL) { DocumentLoader* loader = frame->loader().documentLoader(); if (!loader) - return 0; + return nullptr; RefPtr<ArchiveResource> subresource = loader->subresource(resourceURL); if (!subresource) - return 0; + return nullptr; - return subresource->data(); + return &subresource->data(); } void WebPage::getResourceDataFromFrame(uint64_t frameID, const String& resourceURLString, uint64_t callbackID) { - IPC::DataReference dataReference; - URL resourceURL(URL(), resourceURLString); - RefPtr<SharedBuffer> buffer; - if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) { + if (WebFrame* frame = WebProcess::singleton().webFrame(frameID)) { + URL resourceURL(URL(), resourceURLString); buffer = resourceDataForFrame(frame->coreFrame(), resourceURL); if (!buffer) { // Try to get the resource data from the cache. buffer = cachedResponseDataForURL(resourceURL); } - - if (buffer) - dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()); } + // FIXME: Use SharedBufferDataReference. + IPC::DataReference dataReference; + if (buffer) + dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()); send(Messages::WebPageProxy::DataCallback(dataReference, callbackID)); } void WebPage::getWebArchiveOfFrame(uint64_t frameID, uint64_t callbackID) { - IPC::DataReference dataReference; - -#if PLATFORM(MAC) +#if PLATFORM(COCOA) RetainPtr<CFDataRef> data; - if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) { - if ((data = frame->webArchiveData(0, 0))) - dataReference = IPC::DataReference(CFDataGetBytePtr(data.get()), CFDataGetLength(data.get())); - } + if (WebFrame* frame = WebProcess::singleton().webFrame(frameID)) + data = frame->webArchiveData(nullptr, nullptr); #else UNUSED_PARAM(frameID); #endif + IPC::DataReference dataReference; +#if PLATFORM(COCOA) + if (data) + dataReference = IPC::DataReference(CFDataGetBytePtr(data.get()), CFDataGetLength(data.get())); +#endif send(Messages::WebPageProxy::DataCallback(dataReference, callbackID)); } @@ -2420,7 +2935,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) m_scrollingPerformanceLoggingEnabled = store.getBoolValueForKey(WebPreferencesKey::scrollingPerformanceLoggingEnabledKey()); -#if PLATFORM(MAC) +#if PLATFORM(COCOA) m_pdfPluginEnabled = store.getBoolValueForKey(WebPreferencesKey::pdfPluginEnabledKey()); #endif @@ -2428,7 +2943,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) // but we currently don't match the naming of WebCore exactly so we are // handrolling the boolean and integer preferences until that is fixed. -#define INITIALIZE_SETTINGS(KeyUpper, KeyLower, TypeName, Type, DefaultValue) settings.set##KeyUpper(store.get##TypeName##ValueForKey(WebPreferencesKey::KeyLower##Key())); +#define INITIALIZE_SETTINGS(KeyUpper, KeyLower, TypeName, Type, DefaultValue, HumanReadableName, HumanReadableDescription) settings.set##KeyUpper(store.get##TypeName##ValueForKey(WebPreferencesKey::KeyLower##Key())); FOR_EACH_WEBKIT_STRING_PREFERENCE(INITIALIZE_SETTINGS) @@ -2445,17 +2960,18 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings.setLocalStorageEnabled(store.getBoolValueForKey(WebPreferencesKey::localStorageEnabledKey())); settings.setXSSAuditorEnabled(store.getBoolValueForKey(WebPreferencesKey::xssAuditorEnabledKey())); settings.setFrameFlatteningEnabled(store.getBoolValueForKey(WebPreferencesKey::frameFlatteningEnabledKey())); - if (m_sessionID) - settings.setPrivateBrowsingEnabled(SessionTracker::isEphemeralID(m_sessionID)); - else - settings.setPrivateBrowsingEnabled(store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey())); + if (store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey()) && !usesEphemeralSession()) + setSessionID(SessionID::legacyPrivateSessionID()); + else if (!store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey()) && sessionID() == SessionID::legacyPrivateSessionID()) + setSessionID(SessionID::defaultSessionID()); settings.setDeveloperExtrasEnabled(store.getBoolValueForKey(WebPreferencesKey::developerExtrasEnabledKey())); - settings.setJavaScriptExperimentsEnabled(store.getBoolValueForKey(WebPreferencesKey::javaScriptExperimentsEnabledKey())); + settings.setJavaScriptRuntimeFlags(RuntimeFlags(store.getUInt32ValueForKey(WebPreferencesKey::javaScriptRuntimeFlagsKey()))); settings.setTextAreasAreResizable(store.getBoolValueForKey(WebPreferencesKey::textAreasAreResizableKey())); settings.setNeedsSiteSpecificQuirks(store.getBoolValueForKey(WebPreferencesKey::needsSiteSpecificQuirksKey())); settings.setJavaScriptCanOpenWindowsAutomatically(store.getBoolValueForKey(WebPreferencesKey::javaScriptCanOpenWindowsAutomaticallyKey())); settings.setForceFTPDirectoryListings(store.getBoolValueForKey(WebPreferencesKey::forceFTPDirectoryListingsKey())); settings.setDNSPrefetchingEnabled(store.getBoolValueForKey(WebPreferencesKey::dnsPrefetchingEnabledKey())); + settings.setDOMTimersThrottlingEnabled(store.getBoolValueForKey(WebPreferencesKey::domTimersThrottlingEnabledKey())); #if ENABLE(WEB_ARCHIVE) settings.setWebArchiveDebugModeEnabled(store.getBoolValueForKey(WebPreferencesKey::webArchiveDebugModeEnabledKey())); #endif @@ -2470,16 +2986,12 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings.setWebSecurityEnabled(store.getBoolValueForKey(WebPreferencesKey::webSecurityEnabledKey())); settings.setAllowUniversalAccessFromFileURLs(store.getBoolValueForKey(WebPreferencesKey::allowUniversalAccessFromFileURLsKey())); settings.setAllowFileAccessFromFileURLs(store.getBoolValueForKey(WebPreferencesKey::allowFileAccessFromFileURLsKey())); + settings.setNeedsStorageAccessFromFileURLsQuirk(store.getBoolValueForKey(WebPreferencesKey::needsStorageAccessFromFileURLsQuirkKey())); - settings.setMinimumFontSize(store.getUInt32ValueForKey(WebPreferencesKey::minimumFontSizeKey())); - settings.setMinimumLogicalFontSize(store.getUInt32ValueForKey(WebPreferencesKey::minimumLogicalFontSizeKey())); - settings.setDefaultFontSize(store.getUInt32ValueForKey(WebPreferencesKey::defaultFontSizeKey())); - settings.setDefaultFixedFontSize(store.getUInt32ValueForKey(WebPreferencesKey::defaultFixedFontSizeKey())); - settings.setScreenFontSubstitutionEnabled(store.getBoolValueForKey(WebPreferencesKey::screenFontSubstitutionEnabledKey()) -#if PLATFORM(MAC) - || WebProcess::shared().shouldForceScreenFontSubstitution() -#endif - ); + settings.setMinimumFontSize(store.getDoubleValueForKey(WebPreferencesKey::minimumFontSizeKey())); + settings.setMinimumLogicalFontSize(store.getDoubleValueForKey(WebPreferencesKey::minimumLogicalFontSizeKey())); + settings.setDefaultFontSize(store.getDoubleValueForKey(WebPreferencesKey::defaultFontSizeKey())); + settings.setDefaultFixedFontSize(store.getDoubleValueForKey(WebPreferencesKey::defaultFixedFontSizeKey())); settings.setLayoutFallbackWidth(store.getUInt32ValueForKey(WebPreferencesKey::layoutFallbackWidthKey())); settings.setDeviceWidth(store.getUInt32ValueForKey(WebPreferencesKey::deviceWidthKey())); settings.setDeviceHeight(store.getUInt32ValueForKey(WebPreferencesKey::deviceHeightKey())); @@ -2487,35 +2999,57 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings.setShowsToolTipOverTruncatedText(store.getBoolValueForKey(WebPreferencesKey::showsToolTipOverTruncatedTextKey())); settings.setAcceleratedCompositingForOverflowScrollEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingForOverflowScrollEnabledKey())); - settings.setAcceleratedCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingEnabledKey()) && LayerTreeHost::supportsAcceleratedCompositing()); - settings.setAcceleratedDrawingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedDrawingEnabledKey()) && LayerTreeHost::supportsAcceleratedCompositing()); - settings.setCanvasUsesAcceleratedDrawing(store.getBoolValueForKey(WebPreferencesKey::canvasUsesAcceleratedDrawingKey()) && LayerTreeHost::supportsAcceleratedCompositing()); + settings.setAcceleratedCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingEnabledKey())); + settings.setAcceleratedDrawingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedDrawingEnabledKey())); + settings.setDisplayListDrawingEnabled(store.getBoolValueForKey(WebPreferencesKey::displayListDrawingEnabledKey())); + settings.setCanvasUsesAcceleratedDrawing(store.getBoolValueForKey(WebPreferencesKey::canvasUsesAcceleratedDrawingKey())); settings.setShowDebugBorders(store.getBoolValueForKey(WebPreferencesKey::compositingBordersVisibleKey())); settings.setShowRepaintCounter(store.getBoolValueForKey(WebPreferencesKey::compositingRepaintCountersVisibleKey())); settings.setShowTiledScrollingIndicator(store.getBoolValueForKey(WebPreferencesKey::tiledScrollingIndicatorVisibleKey())); + settings.setVisibleDebugOverlayRegions(store.getUInt32ValueForKey(WebPreferencesKey::visibleDebugOverlayRegionsKey())); + settings.setUseGiantTiles(store.getBoolValueForKey(WebPreferencesKey::useGiantTilesKey())); + settings.setAggressiveTileRetentionEnabled(store.getBoolValueForKey(WebPreferencesKey::aggressiveTileRetentionEnabledKey())); - RuntimeEnabledFeatures::sharedFeatures().setCSSRegionsEnabled(store.getBoolValueForKey(WebPreferencesKey::cssRegionsEnabledKey())); - RuntimeEnabledFeatures::sharedFeatures().setCSSCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::cssCompositingEnabledKey())); - settings.setCSSGridLayoutEnabled(store.getBoolValueForKey(WebPreferencesKey::cssGridLayoutEnabledKey())); - settings.setRegionBasedColumnsEnabled(store.getBoolValueForKey(WebPreferencesKey::regionBasedColumnsEnabledKey())); + settings.setTemporaryTileCohortRetentionEnabled(store.getBoolValueForKey(WebPreferencesKey::temporaryTileCohortRetentionEnabledKey())); +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + RuntimeEnabledFeatures::sharedFeatures().setAnimationTriggersEnabled(store.getBoolValueForKey(WebPreferencesKey::cssAnimationTriggersEnabledKey())); +#endif +#if ENABLE(WEB_ANIMATIONS) + RuntimeEnabledFeatures::sharedFeatures().setWebAnimationsEnabled(store.getBoolValueForKey(WebPreferencesKey::webAnimationsEnabledKey())); +#endif settings.setWebGLEnabled(store.getBoolValueForKey(WebPreferencesKey::webGLEnabledKey())); - settings.setMultithreadedWebGLEnabled(store.getBoolValueForKey(WebPreferencesKey::multithreadedWebGLEnabledKey())); settings.setForceSoftwareWebGLRendering(store.getBoolValueForKey(WebPreferencesKey::forceSoftwareWebGLRenderingKey())); settings.setAccelerated2dCanvasEnabled(store.getBoolValueForKey(WebPreferencesKey::accelerated2dCanvasEnabledKey())); - settings.setMediaPlaybackRequiresUserGesture(store.getBoolValueForKey(WebPreferencesKey::mediaPlaybackRequiresUserGestureKey())); - settings.setMediaPlaybackAllowsInline(store.getBoolValueForKey(WebPreferencesKey::mediaPlaybackAllowsInlineKey())); + bool requiresUserGestureForMedia = store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureForMediaPlaybackKey()); + settings.setVideoPlaybackRequiresUserGesture(requiresUserGestureForMedia || store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureForVideoPlaybackKey())); + settings.setAudioPlaybackRequiresUserGesture(requiresUserGestureForMedia || store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureForAudioPlaybackKey())); + settings.setRequiresUserGestureToLoadVideo(store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureToLoadVideoKey())); + settings.setMainContentUserGestureOverrideEnabled(store.getBoolValueForKey(WebPreferencesKey::mainContentUserGestureOverrideEnabledKey())); + settings.setAllowsInlineMediaPlayback(store.getBoolValueForKey(WebPreferencesKey::allowsInlineMediaPlaybackKey())); + settings.setAllowsInlineMediaPlaybackAfterFullscreen(store.getBoolValueForKey(WebPreferencesKey::allowsInlineMediaPlaybackAfterFullscreenKey())); + settings.setInlineMediaPlaybackRequiresPlaysInlineAttribute(store.getBoolValueForKey(WebPreferencesKey::inlineMediaPlaybackRequiresPlaysInlineAttributeKey())); + settings.setInvisibleAutoplayNotPermitted(store.getBoolValueForKey(WebPreferencesKey::invisibleAutoplayNotPermittedKey())); + settings.setMediaDataLoadsAutomatically(store.getBoolValueForKey(WebPreferencesKey::mediaDataLoadsAutomaticallyKey())); +#if ENABLE(ATTACHMENT_ELEMENT) + settings.setAttachmentElementEnabled(store.getBoolValueForKey(WebPreferencesKey::attachmentElementEnabledKey())); +#endif + settings.setAllowsPictureInPictureMediaPlayback(store.getBoolValueForKey(WebPreferencesKey::allowsPictureInPictureMediaPlaybackKey())); + settings.setMediaControlsScaleWithPageZoom(store.getBoolValueForKey(WebPreferencesKey::mediaControlsScaleWithPageZoomKey())); settings.setMockScrollbarsEnabled(store.getBoolValueForKey(WebPreferencesKey::mockScrollbarsEnabledKey())); settings.setHyperlinkAuditingEnabled(store.getBoolValueForKey(WebPreferencesKey::hyperlinkAuditingEnabledKey())); settings.setRequestAnimationFrameEnabled(store.getBoolValueForKey(WebPreferencesKey::requestAnimationFrameEnabledKey())); #if ENABLE(SMOOTH_SCROLLING) settings.setScrollAnimatorEnabled(store.getBoolValueForKey(WebPreferencesKey::scrollAnimatorEnabledKey())); #endif + settings.setForceUpdateScrollbarsOnMainThreadForPerformanceTesting(store.getBoolValueForKey(WebPreferencesKey::forceUpdateScrollbarsOnMainThreadForPerformanceTestingKey())); settings.setInteractiveFormValidationEnabled(store.getBoolValueForKey(WebPreferencesKey::interactiveFormValidationEnabledKey())); settings.setSpatialNavigationEnabled(store.getBoolValueForKey(WebPreferencesKey::spatialNavigationEnabledKey())); -#if ENABLE(SQL_DATABASE) - DatabaseManager::manager().setIsAvailable(store.getBoolValueForKey(WebPreferencesKey::databasesEnabledKey())); -#endif + settings.setHttpEquivEnabled(store.getBoolValueForKey(WebPreferencesKey::httpEquivEnabledKey())); + + settings.setSelectionPaintingWithoutSelectionGapsEnabled(store.getBoolValueForKey(WebPreferencesKey::selectionPaintingWithoutSelectionGapsEnabledKey())); + + DatabaseManager::singleton().setIsAvailable(store.getBoolValueForKey(WebPreferencesKey::databasesEnabledKey())); #if ENABLE(FULLSCREEN_API) settings.setFullScreenEnabled(store.getBoolValueForKey(WebPreferencesKey::fullScreenEnabledKey())); @@ -2523,14 +3057,19 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) #if USE(AVFOUNDATION) settings.setAVFoundationEnabled(store.getBoolValueForKey(WebPreferencesKey::isAVFoundationEnabledKey())); + settings.setAVFoundationNSURLSessionEnabled(store.getBoolValueForKey(WebPreferencesKey::isAVFoundationNSURLSessionEnabledKey())); #endif -#if PLATFORM(MAC) +#if USE(GSTREAMER) + settings.setGStreamerEnabled(store.getBoolValueForKey(WebPreferencesKey::isGStreamerEnabledKey())); +#endif + +#if PLATFORM(COCOA) settings.setQTKitEnabled(store.getBoolValueForKey(WebPreferencesKey::isQTKitEnabledKey())); #endif -#if USE(PLUGIN_PROXY_FOR_VIDEO) - settings->setVideoPluginProxyEnabled(store.getBoolValueForKey(WebPreferencesKey::isVideoPluginProxyEnabledKey())); +#if PLATFORM(IOS) && HAVE(AVKIT) + settings.setAVKitEnabled(true); #endif #if ENABLE(WEB_AUDIO) @@ -2538,10 +3077,25 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) #endif #if ENABLE(MEDIA_STREAM) - settings.setMediaStreamEnabled(store.getBoolValueForKey(WebPreferencesKey::mediaStreamEnabledKey())); + RuntimeEnabledFeatures::sharedFeatures().setMediaStreamEnabled(store.getBoolValueForKey(WebPreferencesKey::mediaStreamEnabledKey())); +#endif + +#if ENABLE(WEB_RTC) + RuntimeEnabledFeatures::sharedFeatures().setPeerConnectionEnabled(store.getBoolValueForKey(WebPreferencesKey::peerConnectionEnabledKey())); +#endif + +#if ENABLE(SERVICE_CONTROLS) + settings.setImageControlsEnabled(store.getBoolValueForKey(WebPreferencesKey::imageControlsEnabledKey())); +#endif + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + settings.setAllowsAirPlayForMediaPlayback(store.getBoolValueForKey(WebPreferencesKey::allowsAirPlayForMediaPlaybackKey())); +#endif + +#if ENABLE(RESOURCE_USAGE) + settings.setResourceUsageOverlayVisible(store.getBoolValueForKey(WebPreferencesKey::resourceUsageOverlayVisibleKey())); #endif - settings.setApplicationChromeMode(store.getBoolValueForKey(WebPreferencesKey::applicationChromeModeKey())); settings.setSuppressesIncrementalRendering(store.getBoolValueForKey(WebPreferencesKey::suppressesIncrementalRenderingKey())); settings.setIncrementalRenderingSuppressionTimeoutInSeconds(store.getDoubleValueForKey(WebPreferencesKey::incrementalRenderingSuppressionTimeoutKey())); settings.setBackspaceKeyNavigationEnabled(store.getBoolValueForKey(WebPreferencesKey::backspaceKeyNavigationEnabledKey())); @@ -2574,6 +3128,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) #if ENABLE(TEXT_AUTOSIZING) settings.setTextAutosizingEnabled(store.getBoolValueForKey(WebPreferencesKey::textAutosizingEnabledKey())); + settings.setMinimumZoomFontSize(store.getDoubleValueForKey(WebPreferencesKey::minimumZoomFontSizeKey())); #endif settings.setLogsPageMessagesToSystemConsoleEnabled(store.getBoolValueForKey(WebPreferencesKey::logsPageMessagesToSystemConsoleEnabledKey())); @@ -2583,16 +3138,18 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings.setSelectTrailingWhitespaceEnabled(store.getBoolValueForKey(WebPreferencesKey::selectTrailingWhitespaceEnabledKey())); settings.setShowsURLsInToolTips(store.getBoolValueForKey(WebPreferencesKey::showsURLsInToolTipsEnabledKey())); -#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) settings.setHiddenPageDOMTimerThrottlingEnabled(store.getBoolValueForKey(WebPreferencesKey::hiddenPageDOMTimerThrottlingEnabledKey())); -#endif -#if ENABLE(PAGE_VISIBILITY_API) - settings.setHiddenPageCSSAnimationSuspensionEnabled(store.getBoolValueForKey(WebPreferencesKey::hiddenPageCSSAnimationSuspensionEnabledKey())); -#endif + settings.setHiddenPageDOMTimerThrottlingAutoIncreases(store.getBoolValueForKey(WebPreferencesKey::hiddenPageDOMTimerThrottlingAutoIncreasesKey())); + settings.setHiddenPageCSSAnimationSuspensionEnabled(store.getBoolValueForKey(WebPreferencesKey::hiddenPageCSSAnimationSuspensionEnabledKey())); settings.setLowPowerVideoAudioBufferSizeEnabled(store.getBoolValueForKey(WebPreferencesKey::lowPowerVideoAudioBufferSizeEnabledKey())); settings.setSimpleLineLayoutEnabled(store.getBoolValueForKey(WebPreferencesKey::simpleLineLayoutEnabledKey())); settings.setSimpleLineLayoutDebugBordersEnabled(store.getBoolValueForKey(WebPreferencesKey::simpleLineLayoutDebugBordersEnabledKey())); + + settings.setNewBlockInsideInlineModelEnabled(store.getBoolValueForKey(WebPreferencesKey::newBlockInsideInlineModelEnabledKey())); + settings.setDeferredCSSParserEnabled(store.getBoolValueForKey(WebPreferencesKey::deferredCSSParserEnabledKey())); + + settings.setSubpixelCSSOMElementMetricsEnabled(store.getBoolValueForKey(WebPreferencesKey::subpixelCSSOMElementMetricsEnabledKey())); settings.setUseLegacyTextAlignPositionedElementBehavior(store.getBoolValueForKey(WebPreferencesKey::useLegacyTextAlignPositionedElementBehaviorKey())); @@ -2600,29 +3157,229 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings.setMediaSourceEnabled(store.getBoolValueForKey(WebPreferencesKey::mediaSourceEnabledKey())); #endif - if (store.getBoolValueForKey(WebPreferencesKey::pageVisibilityBasedProcessSuppressionEnabledKey())) { - if (m_processSuppressionDisabledByWebPreference.isActive()) - m_processSuppressionDisabledByWebPreference.endActivity(); - } else { - if (!m_processSuppressionDisabledByWebPreference.isActive()) - m_processSuppressionDisabledByWebPreference.beginActivity(); +#if ENABLE(MEDIA_STREAM) + settings.setMockCaptureDevicesEnabled(store.getBoolValueForKey(WebPreferencesKey::mockCaptureDevicesEnabledKey())); + settings.setMediaCaptureRequiresSecureConnection(store.getBoolValueForKey(WebPreferencesKey::mediaCaptureRequiresSecureConnectionKey())); +#endif + + settings.setShouldConvertPositionStyleOnCopy(store.getBoolValueForKey(WebPreferencesKey::shouldConvertPositionStyleOnCopyKey())); + + settings.setStandalone(store.getBoolValueForKey(WebPreferencesKey::standaloneKey())); + settings.setTelephoneNumberParsingEnabled(store.getBoolValueForKey(WebPreferencesKey::telephoneNumberParsingEnabledKey())); + settings.setAllowMultiElementImplicitSubmission(store.getBoolValueForKey(WebPreferencesKey::allowMultiElementImplicitSubmissionKey())); + settings.setAlwaysUseAcceleratedOverflowScroll(store.getBoolValueForKey(WebPreferencesKey::alwaysUseAcceleratedOverflowScrollKey())); + + settings.setPasswordEchoEnabled(store.getBoolValueForKey(WebPreferencesKey::passwordEchoEnabledKey())); + settings.setPasswordEchoDurationInSeconds(store.getDoubleValueForKey(WebPreferencesKey::passwordEchoDurationKey())); + + settings.setLayoutInterval(Seconds(store.getDoubleValueForKey(WebPreferencesKey::layoutIntervalKey()))); + settings.setMaxParseDuration(store.getDoubleValueForKey(WebPreferencesKey::maxParseDurationKey())); + + settings.setEnableInheritURIQueryComponent(store.getBoolValueForKey(WebPreferencesKey::enableInheritURIQueryComponentKey())); + + settings.setShouldDispatchJavaScriptWindowOnErrorEvents(true); + + auto userInterfaceDirectionPolicyCandidate = static_cast<WebCore::UserInterfaceDirectionPolicy>(store.getUInt32ValueForKey(WebPreferencesKey::userInterfaceDirectionPolicyKey())); + if (userInterfaceDirectionPolicyCandidate == WebCore::UserInterfaceDirectionPolicy::Content || userInterfaceDirectionPolicyCandidate == WebCore::UserInterfaceDirectionPolicy::System) + settings.setUserInterfaceDirectionPolicy(userInterfaceDirectionPolicyCandidate); + TextDirection systemLayoutDirectionCandidate = static_cast<TextDirection>(store.getUInt32ValueForKey(WebPreferencesKey::systemLayoutDirectionKey())); + if (systemLayoutDirectionCandidate == WebCore::LTR || systemLayoutDirectionCandidate == WebCore::RTL) + settings.setSystemLayoutDirection(systemLayoutDirectionCandidate); + +#if ENABLE(APPLE_PAY) + settings.setApplePayEnabled(store.getBoolValueForKey(WebPreferencesKey::applePayEnabledKey())); + settings.setApplePayCapabilityDisclosureAllowed(store.getBoolValueForKey(WebPreferencesKey::applePayCapabilityDisclosureAllowedKey())); +#endif + +#if PLATFORM(IOS) + settings.setUseImageDocumentForSubframePDF(true); +#endif + +#if ENABLE(DATA_DETECTION) + settings.setDataDetectorTypes(static_cast<DataDetectorTypes>(store.getUInt32ValueForKey(WebPreferencesKey::dataDetectorTypesKey()))); +#endif +#if ENABLE(GAMEPAD) + RuntimeEnabledFeatures::sharedFeatures().setGamepadsEnabled(store.getBoolValueForKey(WebPreferencesKey::gamepadsEnabledKey())); +#endif + +#if ENABLE(SERVICE_CONTROLS) + settings.setServiceControlsEnabled(store.getBoolValueForKey(WebPreferencesKey::serviceControlsEnabledKey())); +#endif + +#if ENABLE(FETCH_API) + RuntimeEnabledFeatures::sharedFeatures().setFetchAPIEnabled(store.getBoolValueForKey(WebPreferencesKey::fetchAPIEnabledKey())); +#endif + +#if ENABLE(DOWNLOAD_ATTRIBUTE) + RuntimeEnabledFeatures::sharedFeatures().setDownloadAttributeEnabled(store.getBoolValueForKey(WebPreferencesKey::downloadAttributeEnabledKey())); +#endif + + RuntimeEnabledFeatures::sharedFeatures().setShadowDOMEnabled(store.getBoolValueForKey(WebPreferencesKey::shadowDOMEnabledKey())); + + RuntimeEnabledFeatures::sharedFeatures().setInteractiveFormValidationEnabled(store.getBoolValueForKey(WebPreferencesKey::interactiveFormValidationEnabledKey())); + + // Experimental Features. + + RuntimeEnabledFeatures::sharedFeatures().setCSSGridLayoutEnabled(store.getBoolValueForKey(WebPreferencesKey::cssGridLayoutEnabledKey())); + + RuntimeEnabledFeatures::sharedFeatures().setCustomElementsEnabled(store.getBoolValueForKey(WebPreferencesKey::customElementsEnabledKey())); + +#if ENABLE(WEBGL2) + RuntimeEnabledFeatures::sharedFeatures().setWebGL2Enabled(store.getBoolValueForKey(WebPreferencesKey::webGL2EnabledKey())); +#endif + + settings.setSpringTimingFunctionEnabled(store.getBoolValueForKey(WebPreferencesKey::springTimingFunctionEnabledKey())); + + settings.setVisualViewportEnabled(store.getBoolValueForKey(WebPreferencesKey::visualViewportEnabledKey())); + + settings.setInputEventsEnabled(store.getBoolValueForKey(WebPreferencesKey::inputEventsEnabledKey())); + RuntimeEnabledFeatures::sharedFeatures().setInputEventsEnabled(store.getBoolValueForKey(WebPreferencesKey::inputEventsEnabledKey())); + + RuntimeEnabledFeatures::sharedFeatures().setModernMediaControlsEnabled(store.getBoolValueForKey(WebPreferencesKey::modernMediaControlsEnabledKey())); + +#if ENABLE(ENCRYPTED_MEDIA) + RuntimeEnabledFeatures::sharedFeatures().setEncryptedMediaAPIEnabled(store.getBoolValueForKey(WebPreferencesKey::encryptedMediaAPIEnabledKey())); +#endif + +#if ENABLE(INTERSECTION_OBSERVER) + RuntimeEnabledFeatures::sharedFeatures().setIntersectionObserverEnabled(store.getBoolValueForKey(WebPreferencesKey::intersectionObserverEnabledKey())); +#endif + + RuntimeEnabledFeatures::sharedFeatures().setUserTimingEnabled(store.getBoolValueForKey(WebPreferencesKey::userTimingEnabledKey())); + RuntimeEnabledFeatures::sharedFeatures().setResourceTimingEnabled(store.getBoolValueForKey(WebPreferencesKey::resourceTimingEnabledKey())); + RuntimeEnabledFeatures::sharedFeatures().setLinkPreloadEnabled(store.getBoolValueForKey(WebPreferencesKey::linkPreloadEnabledKey())); + + bool processSuppressionEnabled = store.getBoolValueForKey(WebPreferencesKey::pageVisibilityBasedProcessSuppressionEnabledKey()); + if (m_processSuppressionEnabled != processSuppressionEnabled) { + m_processSuppressionEnabled = processSuppressionEnabled; + updateThrottleState(); } +#if ENABLE(SUBTLE_CRYPTO) + RuntimeEnabledFeatures::sharedFeatures().setSubtleCryptoEnabled(store.getBoolValueForKey(WebPreferencesKey::subtleCryptoEnabledKey())); +#endif + platformPreferencesDidChange(store); if (m_drawingArea) m_drawingArea->updatePreferences(store); + +#if PLATFORM(IOS) + m_ignoreViewportScalingConstraints = store.getBoolValueForKey(WebPreferencesKey::ignoreViewportScalingConstraintsKey()); + m_viewportConfiguration.setCanIgnoreScalingConstraints(m_ignoreViewportScalingConstraints); + setForceAlwaysUserScalable(m_forceAlwaysUserScalable || store.getBoolValueForKey(WebPreferencesKey::forceAlwaysUserScalableKey())); +#endif + settings.setLargeImageAsyncDecodingEnabled(store.getBoolValueForKey(WebPreferencesKey::largeImageAsyncDecodingEnabledKey())); + settings.setAnimatedImageAsyncDecodingEnabled(store.getBoolValueForKey(WebPreferencesKey::animatedImageAsyncDecodingEnabledKey())); + settings.setShouldSuppressKeyboardInputDuringProvisionalNavigation(store.getBoolValueForKey(WebPreferencesKey::shouldSuppressKeyboardInputDuringProvisionalNavigationKey())); +} + +#if ENABLE(DATA_DETECTION) +void WebPage::setDataDetectionResults(NSArray *detectionResults) +{ + DataDetectionResult dataDetectionResult; + dataDetectionResult.results = detectionResults; + send(Messages::WebPageProxy::SetDataDetectionResult(dataDetectionResult)); +} +#endif + +#if PLATFORM(COCOA) +void WebPage::willCommitLayerTree(RemoteLayerTreeTransaction& layerTransaction) +{ + FrameView* frameView = corePage()->mainFrame().view(); + if (!frameView) + return; + + layerTransaction.setContentsSize(frameView->contentsSize()); + layerTransaction.setScrollOrigin(frameView->scrollOrigin()); + layerTransaction.setPageScaleFactor(corePage()->pageScaleFactor()); + layerTransaction.setRenderTreeSize(corePage()->renderTreeSize()); + layerTransaction.setPageExtendedBackgroundColor(corePage()->pageExtendedBackgroundColor()); + + layerTransaction.setBaseLayoutViewportSize(frameView->baseLayoutViewportSize()); + layerTransaction.setMinStableLayoutViewportOrigin(frameView->minStableLayoutViewportOrigin()); + layerTransaction.setMaxStableLayoutViewportOrigin(frameView->maxStableLayoutViewportOrigin()); + +#if PLATFORM(IOS) + layerTransaction.setScaleWasSetByUIProcess(scaleWasSetByUIProcess()); + layerTransaction.setMinimumScaleFactor(m_viewportConfiguration.minimumScale()); + layerTransaction.setMaximumScaleFactor(m_viewportConfiguration.maximumScale()); + layerTransaction.setInitialScaleFactor(m_viewportConfiguration.initialScale()); + layerTransaction.setViewportMetaTagWidth(m_viewportConfiguration.viewportArguments().width); + layerTransaction.setViewportMetaTagWidthWasExplicit(m_viewportConfiguration.viewportArguments().widthWasExplicit); + layerTransaction.setViewportMetaTagCameFromImageDocument(m_viewportConfiguration.viewportArguments().type == ViewportArguments::ImageDocument); + layerTransaction.setIsInStableState(m_isInStableState); + layerTransaction.setAllowsUserScaling(allowsUserScaling()); +#endif + +#if PLATFORM(MAC) + layerTransaction.setScrollPosition(frameView->scrollPosition()); +#endif } -#if ENABLE(INSPECTOR) -WebInspector* WebPage::inspector() +void WebPage::didFlushLayerTreeAtTime(MonotonicTime timestamp) +{ +#if PLATFORM(IOS) + if (m_oldestNonStableUpdateVisibleContentRectsTimestamp != MonotonicTime()) { + Seconds elapsed = timestamp - m_oldestNonStableUpdateVisibleContentRectsTimestamp; + m_oldestNonStableUpdateVisibleContentRectsTimestamp = MonotonicTime(); + + m_estimatedLatency = m_estimatedLatency * 0.80 + elapsed * 0.20; + } +#else + UNUSED_PARAM(timestamp); +#endif +} +#endif + +WebInspector* WebPage::inspector(LazyCreationPolicy behavior) { if (m_isClosed) - return 0; - if (!m_inspector) - m_inspector = WebInspector::create(this, m_inspectorClient); + return nullptr; + if (!m_inspector && behavior == LazyCreationPolicy::CreateIfNeeded) + m_inspector = WebInspector::create(this); return m_inspector.get(); } + +WebInspectorUI* WebPage::inspectorUI() +{ + if (m_isClosed) + return nullptr; + if (!m_inspectorUI) + m_inspectorUI = WebInspectorUI::create(*this); + return m_inspectorUI.get(); +} + +RemoteWebInspectorUI* WebPage::remoteInspectorUI() +{ + if (m_isClosed) + return nullptr; + if (!m_remoteInspectorUI) + m_remoteInspectorUI = RemoteWebInspectorUI::create(*this); + return m_remoteInspectorUI.get(); +} + +#if (PLATFORM(IOS) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) +WebPlaybackSessionManager& WebPage::playbackSessionManager() +{ + if (!m_playbackSessionManager) + m_playbackSessionManager = WebPlaybackSessionManager::create(*this); + return *m_playbackSessionManager; +} + +WebVideoFullscreenManager& WebPage::videoFullscreenManager() +{ + if (!m_videoFullscreenManager) + m_videoFullscreenManager = WebVideoFullscreenManager::create(*this, playbackSessionManager()); + return *m_videoFullscreenManager; +} +#endif + +#if PLATFORM(IOS) +void WebPage::setAllowsMediaDocumentInlinePlayback(bool allows) +{ + m_page->setAllowsMediaDocumentInlinePlayback(allows); +} #endif #if ENABLE(FULLSCREEN_API) @@ -2643,7 +3400,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana return m_notificationPermissionRequestManager.get(); } -#if !PLATFORM(GTK) && !PLATFORM(MAC) +#if !PLATFORM(GTK) && !PLATFORM(COCOA) bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* evt) { Node* node = evt->target()->toNode(); @@ -2682,64 +3439,63 @@ bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* evt) #if ENABLE(DRAG_SUPPORT) #if PLATFORM(GTK) -void WebPage::performDragControllerAction(uint64_t action, WebCore::DragData dragData) +void WebPage::performDragControllerAction(uint64_t action, const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t draggingSourceOperationMask, WebSelectionData&& selection, uint32_t flags) { if (!m_page) { - send(Messages::WebPageProxy::DidPerformDragControllerAction(WebCore::DragSession())); - DataObjectGtk* data = const_cast<DataObjectGtk*>(dragData.platformData()); - data->deref(); + send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0)); return; } + DragData dragData(selection.selectionData.ptr(), clientPosition, globalPosition, static_cast<DragOperation>(draggingSourceOperationMask), static_cast<DragApplicationFlags>(flags)); switch (action) { - case DragControllerActionEntered: - send(Messages::WebPageProxy::DidPerformDragControllerAction(m_page->dragController().dragEntered(dragData))); + case DragControllerActionEntered: { + DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData); + send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted())); break; - - case DragControllerActionUpdated: - send(Messages::WebPageProxy::DidPerformDragControllerAction(m_page->dragController().dragUpdated(dragData))); + } + case DragControllerActionUpdated: { + DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData); + send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted())); break; - + } case DragControllerActionExited: m_page->dragController().dragExited(dragData); break; - case DragControllerActionPerformDrag: { - m_page->dragController().performDrag(dragData); + case DragControllerActionPerformDragOperation: { + m_page->dragController().performDragOperation(dragData); break; } default: ASSERT_NOT_REACHED(); } - // DragData does not delete its platformData so we need to do that here. - DataObjectGtk* data = const_cast<DataObjectGtk*>(dragData.platformData()); - data->deref(); } - #else -void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const String& dragStorageName, uint32_t flags, const SandboxExtension::Handle& sandboxExtensionHandle, const SandboxExtension::HandleArray& sandboxExtensionsHandleArray) +void WebPage::performDragControllerAction(uint64_t action, const WebCore::DragData& dragData, const SandboxExtension::Handle& sandboxExtensionHandle, const SandboxExtension::HandleArray& sandboxExtensionsHandleArray) { if (!m_page) { - send(Messages::WebPageProxy::DidPerformDragControllerAction(WebCore::DragSession())); + send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0)); return; } - DragData dragData(dragStorageName, clientPosition, globalPosition, static_cast<DragOperation>(draggingSourceOperationMask), static_cast<DragApplicationFlags>(flags)); switch (action) { - case DragControllerActionEntered: - send(Messages::WebPageProxy::DidPerformDragControllerAction(m_page->dragController().dragEntered(dragData))); + case DragControllerActionEntered: { + DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData); + send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted())); break; - case DragControllerActionUpdated: - send(Messages::WebPageProxy::DidPerformDragControllerAction(m_page->dragController().dragUpdated(dragData))); + } + case DragControllerActionUpdated: { + DragOperation resolvedDragOperation = m_page->dragController().dragUpdated(dragData); + send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted())); break; - + } case DragControllerActionExited: m_page->dragController().dragExited(dragData); break; - case DragControllerActionPerformDrag: { + case DragControllerActionPerformDragOperation: { ASSERT(!m_pendingDropSandboxExtension); m_pendingDropSandboxExtension = SandboxExtension::create(sandboxExtensionHandle); @@ -2748,13 +3504,16 @@ void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint cli m_pendingDropExtensionsForFileUpload.append(extension); } - m_page->dragController().performDrag(dragData); + m_page->dragController().performDragOperation(dragData); // If we started loading a local file, the sandbox extension tracker would have adopted this // pending drop sandbox extension. If not, we'll play it safe and clear it. m_pendingDropSandboxExtension = nullptr; m_pendingDropExtensionsForFileUpload.clear(); +#if ENABLE(DATA_INTERACTION) + send(Messages::WebPageProxy::DidPerformDataInteractionControllerOperation()); +#endif break; } @@ -2774,13 +3533,13 @@ void WebPage::dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint glob if (!view) return; // FIXME: These are fake modifier keys here, but they should be real ones instead. - PlatformMouseEvent event(adjustedClientPosition, adjustedGlobalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime()); + PlatformMouseEvent event(adjustedClientPosition, adjustedGlobalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime(), 0, WebCore::NoTap); m_page->mainFrame().eventHandler().dragSourceEndedAt(event, (DragOperation)operation); } void WebPage::willPerformLoadDragDestinationAction() { - m_sandboxExtensionTracker.willPerformLoadDragDestinationAction(m_pendingDropSandboxExtension.release()); + m_sandboxExtensionTracker.willPerformLoadDragDestinationAction(WTFMove(m_pendingDropSandboxExtension)); } void WebPage::mayPerformUploadDragDestinationAction() @@ -2807,6 +3566,11 @@ void WebPage::removeWebEditCommand(uint64_t stepID) m_undoStepMap.remove(stepID); } +bool WebPage::isAlwaysOnLoggingAllowed() const +{ + return corePage() && corePage()->isAlwaysOnLoggingAllowed(); +} + void WebPage::unapplyEditCommand(uint64_t stepID) { WebUndoStep* step = webUndoStep(stepID); @@ -2838,6 +3602,7 @@ void WebPage::setActivePopupMenu(WebPopupMenu* menu) } #if ENABLE(INPUT_TYPE_COLOR) + void WebPage::setActiveColorChooser(WebColorChooser* colorChooser) { m_activeColorChooser = colorChooser; @@ -2852,11 +3617,12 @@ void WebPage::didChooseColor(const WebCore::Color& color) { m_activeColorChooser->didChooseColor(color); } + #endif -void WebPage::setActiveOpenPanelResultListener(PassRefPtr<WebOpenPanelResultListener> openPanelResultListener) +void WebPage::setActiveOpenPanelResultListener(Ref<WebOpenPanelResultListener>&& openPanelResultListener) { - m_activeOpenPanelResultListener = openPanelResultListener; + m_activeOpenPanelResultListener = WTFMove(openPanelResultListener); } bool WebPage::findStringFromInjectedBundle(const String& target, FindOptions options) @@ -2897,7 +3663,7 @@ void WebPage::countStringMatches(const String& string, uint32_t options, uint32_ void WebPage::didChangeSelectedIndexForActivePopupMenu(int32_t newIndex) { changeSelectedIndex(newIndex); - m_activePopupMenu = 0; + m_activePopupMenu = nullptr; } void WebPage::changeSelectedIndex(int32_t index) @@ -2908,24 +3674,47 @@ void WebPage::changeSelectedIndex(int32_t index) m_activePopupMenu->didChangeSelectedIndex(index); } +#if PLATFORM(IOS) +void WebPage::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& files, const String& displayString, const IPC::DataReference& iconData) +{ + if (!m_activeOpenPanelResultListener) + return; + + RefPtr<Icon> icon; + if (!iconData.isEmpty()) { + RetainPtr<CFDataRef> dataRef = adoptCF(CFDataCreate(nullptr, iconData.data(), iconData.size())); + RetainPtr<CGDataProviderRef> imageProviderRef = adoptCF(CGDataProviderCreateWithCFData(dataRef.get())); + RetainPtr<CGImageRef> imageRef = adoptCF(CGImageCreateWithJPEGDataProvider(imageProviderRef.get(), nullptr, true, kCGRenderingIntentDefault)); + icon = Icon::createIconForImage(imageRef.get()); + } + + m_activeOpenPanelResultListener->didChooseFilesWithDisplayStringAndIcon(files, displayString, icon.get()); + m_activeOpenPanelResultListener = nullptr; +} +#endif + void WebPage::didChooseFilesForOpenPanel(const Vector<String>& files) { if (!m_activeOpenPanelResultListener) return; m_activeOpenPanelResultListener->didChooseFiles(files); - m_activeOpenPanelResultListener = 0; + m_activeOpenPanelResultListener = nullptr; } void WebPage::didCancelForOpenPanel() { - m_activeOpenPanelResultListener = 0; + m_activeOpenPanelResultListener = nullptr; } -#if ENABLE(WEB_PROCESS_SANDBOX) +#if ENABLE(SANDBOX_EXTENSIONS) void WebPage::extendSandboxForFileFromOpenPanel(const SandboxExtension::Handle& handle) { - SandboxExtension::create(handle)->consumePermanently(); + bool result = SandboxExtension::consumePermanently(handle); + if (!result) { + // We have reports of cases where this fails for some unknown reason, <rdar://problem/10156710>. + WTFLogAlways("WebPage::extendSandboxForFileFromOpenPanel(): Could not consume a sandbox extension"); + } } #endif @@ -2941,6 +3730,34 @@ void WebPage::didReceiveNotificationPermissionDecision(uint64_t notificationID, notificationPermissionRequestManager()->didReceiveNotificationPermissionDecision(notificationID, allowed); } +#if ENABLE(MEDIA_STREAM) +void WebPage::userMediaAccessWasGranted(uint64_t userMediaID, const String& audioDeviceUID, const String& videoDeviceUID) +{ + m_userMediaPermissionRequestManager.userMediaAccessWasGranted(userMediaID, audioDeviceUID, videoDeviceUID); +} + +void WebPage::userMediaAccessWasDenied(uint64_t userMediaID, uint64_t reason, String invalidConstraint) +{ + m_userMediaPermissionRequestManager.userMediaAccessWasDenied(userMediaID, static_cast<UserMediaRequest::MediaAccessDenialReason>(reason), invalidConstraint); +} + +void WebPage::didCompleteMediaDeviceEnumeration(uint64_t userMediaID, const Vector<CaptureDevice>& devices, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess) +{ + m_userMediaPermissionRequestManager.didCompleteMediaDeviceEnumeration(userMediaID, devices, deviceIdentifierHashSalt, originHasPersistentAccess); +} +#if ENABLE(SANDBOX_EXTENSIONS) +void WebPage::grantUserMediaDeviceSandboxExtensions(const MediaDeviceSandboxExtensions& extensions) +{ + m_userMediaPermissionRequestManager.grantUserMediaDeviceSandboxExtensions(extensions); +} + +void WebPage::revokeUserMediaDeviceSandboxExtensions(const Vector<String>& extensionIDs) +{ + m_userMediaPermissionRequestManager.revokeUserMediaDeviceSandboxExtensions(extensionIDs); +} +#endif +#endif + #if !PLATFORM(IOS) void WebPage::advanceToNextMisspelling(bool startBeforeSelection) { @@ -3012,7 +3829,7 @@ void WebPage::didSelectItemFromActiveContextMenu(const WebContextMenuItemData& i return; m_contextMenu->itemSelected(item); - m_contextMenu = 0; + m_contextMenu = nullptr; } #endif @@ -3023,17 +3840,47 @@ void WebPage::replaceSelectionWithText(Frame* frame, const String& text) return frame->editor().replaceSelectionWithText(text, selectReplacement, smartReplace); } +#if !PLATFORM(IOS) void WebPage::clearSelection() { m_page->focusController().focusedOrMainFrame().selection().clear(); } +#endif + +void WebPage::restoreSelectionInFocusedEditableElement() +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + if (!frame.selection().isNone()) + return; + + if (auto document = frame.document()) { + if (auto element = document->focusedElement()) + element->updateFocusAppearance(SelectionRestorationMode::Restore, SelectionRevealMode::DoNotReveal); + } +} + +bool WebPage::mainFrameHasCustomContentProvider() const +{ + if (Frame* frame = mainFrame()) { + WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frame->loader().client()); + ASSERT(webFrameLoaderClient); + return webFrameLoaderClient->frameHasCustomContentProvider(); + } + + return false; +} + +void WebPage::addMIMETypeWithCustomContentProvider(const String& mimeType) +{ + m_mimeTypesWithCustomContentProviders.add(mimeType); +} void WebPage::updateMainFrameScrollOffsetPinning() { Frame& frame = m_page->mainFrame(); - IntPoint scrollPosition = frame.view()->scrollPosition(); - IntPoint maximumScrollPosition = frame.view()->maximumScrollPosition(); - IntPoint minimumScrollPosition = frame.view()->minimumScrollPosition(); + ScrollPosition scrollPosition = frame.view()->scrollPosition(); + ScrollPosition maximumScrollPosition = frame.view()->maximumScrollPosition(); + ScrollPosition minimumScrollPosition = frame.view()->minimumScrollPosition(); bool isPinnedToLeftSide = (scrollPosition.x() <= minimumScrollPosition.x()); bool isPinnedToRightSide = (scrollPosition.x() >= maximumScrollPosition.x()); @@ -3058,21 +3905,17 @@ void WebPage::mainFrameDidLayout() m_cachedPageCount = pageCount; } -#if USE(TILED_BACKING_STORE) && USE(ACCELERATED_COMPOSITING) - if (m_drawingArea && m_drawingArea->layerTreeHost()) { - double red, green, blue, alpha; - m_mainFrame->getDocumentBackgroundColor(&red, &green, &blue, &alpha); - RGBA32 rgba = makeRGBA32FromFloats(red, green, blue, alpha); - if (m_backgroundColor.rgb() != rgba) { - m_backgroundColor.setRGB(rgba); - m_drawingArea->layerTreeHost()->setBackgroundColor(m_backgroundColor); - } - } -#endif - -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) m_viewGestureGeometryCollector.mainFrameDidLayout(); #endif +#if PLATFORM(IOS) + if (FrameView* frameView = mainFrameView()) { + IntSize newContentSize = frameView->contentsSize(); + if (m_viewportConfiguration.setContentsSize(newContentSize)) + viewportConfigurationChanged(); + } + m_findController.redraw(); +#endif } void WebPage::addPluginView(PluginView* pluginView) @@ -3099,13 +3942,13 @@ void WebPage::removePluginView(PluginView* pluginView) void WebPage::sendSetWindowFrame(const FloatRect& windowFrame) { -#if PLATFORM(MAC) +#if PLATFORM(COCOA) m_hasCachedWindowFrame = false; #endif send(Messages::WebPageProxy::SetWindowFrame(windowFrame)); } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) void WebPage::windowAndViewFramesChanged(const FloatRect& windowFrameInScreenCoordinates, const FloatRect& windowFrameInUnflippedScreenCoordinates, const FloatRect& viewFrameInWindowCoordinates, const FloatPoint& accessibilityViewCoordinates) { m_windowFrameInScreenCoordinates = windowFrameInScreenCoordinates; @@ -3145,29 +3988,25 @@ bool WebPage::windowAndWebPageAreFocused() const return m_page->focusController().isFocused() && m_page->focusController().isActive(); } -void WebPage::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder) +void WebPage::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder) { - if (decoder.messageReceiverName() == Messages::DrawingArea::messageReceiverName()) { - if (m_drawingArea) - m_drawingArea->didReceiveDrawingAreaMessage(connection, decoder); + if (decoder.messageReceiverName() == Messages::WebInspector::messageReceiverName()) { + if (WebInspector* inspector = this->inspector()) + inspector->didReceiveMessage(connection, decoder); return; } -#if USE(TILED_BACKING_STORE) && USE(ACCELERATED_COMPOSITING) - if (decoder.messageReceiverName() == Messages::CoordinatedLayerTreeHost::messageReceiverName()) { - if (m_drawingArea) - m_drawingArea->didReceiveCoordinatedLayerTreeHostMessage(connection, decoder); + if (decoder.messageReceiverName() == Messages::WebInspectorUI::messageReceiverName()) { + if (WebInspectorUI* inspectorUI = this->inspectorUI()) + inspectorUI->didReceiveMessage(connection, decoder); return; } -#endif - -#if ENABLE(INSPECTOR) - if (decoder.messageReceiverName() == Messages::WebInspector::messageReceiverName()) { - if (WebInspector* inspector = this->inspector()) - inspector->didReceiveWebInspectorMessage(connection, decoder); + + if (decoder.messageReceiverName() == Messages::RemoteWebInspectorUI::messageReceiverName()) { + if (RemoteWebInspectorUI* remoteInspectorUI = this->remoteInspectorUI()) + remoteInspectorUI->didReceiveMessage(connection, decoder); return; } -#endif #if ENABLE(FULLSCREEN_API) if (decoder.messageReceiverName() == Messages::WebFullScreenManager::messageReceiverName()) { @@ -3179,7 +4018,7 @@ void WebPage::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder didReceiveWebPageMessage(connection, decoder); } -void WebPage::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder) +void WebPage::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder) { didReceiveSyncWebPageMessage(connection, decoder, replyEncoder); } @@ -3243,7 +4082,7 @@ static bool shouldReuseCommittedSandboxExtension(WebFrame* frame) FrameLoadType frameLoadType = frameLoader.loadType(); // If the page is being reloaded, it should reuse whatever extension is committed. - if (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin) + if (frameLoadType == FrameLoadType::Reload || frameLoadType == FrameLoadType::ReloadFromOrigin) return true; DocumentLoader* documentLoader = frameLoader.documentLoader(); @@ -3269,7 +4108,7 @@ void WebPage::SandboxExtensionTracker::didStartProvisionalLoad(WebFrame* frame) ASSERT(!m_provisionalSandboxExtension); - m_provisionalSandboxExtension = m_pendingProvisionalSandboxExtension.release(); + m_provisionalSandboxExtension = WTFMove(m_pendingProvisionalSandboxExtension); if (!m_provisionalSandboxExtension) return; @@ -3286,7 +4125,7 @@ void WebPage::SandboxExtensionTracker::didCommitProvisionalLoad(WebFrame* frame) if (m_committedSandboxExtension) m_committedSandboxExtension->revoke(); - m_committedSandboxExtension = m_provisionalSandboxExtension.release(); + m_committedSandboxExtension = WTFMove(m_provisionalSandboxExtension); // We can also have a non-null m_pendingProvisionalSandboxExtension if a new load is being started. // This extension is not cleared, because it does not pertain to the failed load, and will be needed. @@ -3330,7 +4169,7 @@ void WebPage::didRemoveBackForwardItem(uint64_t itemID) WebBackForwardListProxy::removeItem(itemID); } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) bool WebPage::isSpeaking() { @@ -3350,19 +4189,16 @@ void WebPage::stopSpeaking() #endif -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) RetainPtr<PDFDocument> WebPage::pdfDocumentForPrintingFrame(Frame* coreFrame) { Document* document = coreFrame->document(); - if (!document) - return 0; - - if (!document->isPluginDocument()) - return 0; + if (!is<PluginDocument>(document)) + return nullptr; - PluginView* pluginView = static_cast<PluginView*>(toPluginDocument(document)->pluginWidget()); + PluginView* pluginView = static_cast<PluginView*>(downcast<PluginDocument>(*document).pluginWidget()); if (!pluginView) - return 0; + return nullptr; return pluginView->pdfDocumentForPrinting(); } @@ -3370,7 +4206,7 @@ RetainPtr<PDFDocument> WebPage::pdfDocumentForPrintingFrame(Frame* coreFrame) void WebPage::beginPrinting(uint64_t frameID, const PrintInfo& printInfo) { - WebFrame* frame = WebProcess::shared().webFrame(frameID); + WebFrame* frame = WebProcess::singleton().webFrame(frameID); if (!frame) return; @@ -3378,13 +4214,13 @@ void WebPage::beginPrinting(uint64_t frameID, const PrintInfo& printInfo) if (!coreFrame) return; -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) if (pdfDocumentForPrintingFrame(coreFrame)) return; #endif // PLATFORM(MAC) if (!m_printContext) - m_printContext = adoptPtr(new PrintContext(coreFrame)); + m_printContext = std::make_unique<PrintContext>(coreFrame); drawingArea()->setLayerTreeStateIsFrozen(true); m_printContext->begin(printInfo.availablePaperWidth, printInfo.availablePaperHeight); @@ -3408,6 +4244,13 @@ void WebPage::computePagesForPrinting(uint64_t frameID, const PrintInfo& printIn { Vector<IntRect> resultPageRects; double resultTotalScaleFactorForPrinting = 1; + computePagesForPrintingImpl(frameID, printInfo, resultPageRects, resultTotalScaleFactorForPrinting); + send(Messages::WebPageProxy::ComputedPagesCallback(resultPageRects, resultTotalScaleFactorForPrinting, callbackID)); +} + +void WebPage::computePagesForPrintingImpl(uint64_t frameID, const PrintInfo& printInfo, Vector<WebCore::IntRect>& resultPageRects, double& resultTotalScaleFactorForPrinting) +{ + ASSERT(resultPageRects.isEmpty()); beginPrinting(frameID, printInfo); @@ -3415,41 +4258,43 @@ void WebPage::computePagesForPrinting(uint64_t frameID, const PrintInfo& printIn resultPageRects = m_printContext->pageRects(); resultTotalScaleFactorForPrinting = m_printContext->computeAutomaticScaleFactor(FloatSize(printInfo.availablePaperWidth, printInfo.availablePaperHeight)) * printInfo.pageSetupScaleFactor; } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) else computePagesForPrintingPDFDocument(frameID, printInfo, resultPageRects); -#endif // PLATFORM(MAC) +#endif // PLATFORM(COCOA) // If we're asked to print, we should actually print at least a blank page. if (resultPageRects.isEmpty()) resultPageRects.append(IntRect(0, 0, 1, 1)); - - send(Messages::WebPageProxy::ComputedPagesCallback(resultPageRects, resultTotalScaleFactorForPrinting, callbackID)); } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) void WebPage::drawRectToImage(uint64_t frameID, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, uint64_t callbackID) { - WebFrame* frame = WebProcess::shared().webFrame(frameID); + WebFrame* frame = WebProcess::singleton().webFrame(frameID); Frame* coreFrame = frame ? frame->coreFrame() : 0; RefPtr<WebImage> image; #if USE(CG) if (coreFrame) { -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) ASSERT(coreFrame->document()->printing() || pdfDocumentForPrintingFrame(coreFrame)); #else ASSERT(coreFrame->document()->printing()); #endif - RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(imageSize, ShareableBitmap::SupportsAlpha); + auto bitmap = ShareableBitmap::createShareable(imageSize, ShareableBitmap::SupportsAlpha); + if (!bitmap) { + ASSERT_NOT_REACHED(); + return; + } auto graphicsContext = bitmap->createGraphicsContext(); float printingScale = static_cast<float>(imageSize.width()) / rect.width(); - graphicsContext->scale(FloatSize(printingScale, printingScale)); + graphicsContext->scale(printingScale); -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) if (RetainPtr<PDFDocument> pdfDocument = pdfDocumentForPrintingFrame(coreFrame)) { ASSERT(!m_printContext); graphicsContext->scale(FloatSize(1, -1)); @@ -3461,29 +4306,36 @@ void WebPage::drawRectToImage(uint64_t frameID, const PrintInfo& printInfo, cons m_printContext->spoolRect(*graphicsContext, rect); } - image = WebImage::create(bitmap.release()); + image = WebImage::create(bitmap.releaseNonNull()); } #endif ShareableBitmap::Handle handle; if (image) - image->bitmap()->createHandle(handle, SharedMemory::ReadOnly); + image->bitmap().createHandle(handle, SharedMemory::Protection::ReadOnly); send(Messages::WebPageProxy::ImageCallback(handle, callbackID)); } void WebPage::drawPagesToPDF(uint64_t frameID, const PrintInfo& printInfo, uint32_t first, uint32_t count, uint64_t callbackID) { - WebFrame* frame = WebProcess::shared().webFrame(frameID); + RetainPtr<CFMutableDataRef> pdfPageData; + drawPagesToPDFImpl(frameID, printInfo, first, count, pdfPageData); + send(Messages::WebPageProxy::DataCallback(IPC::DataReference(CFDataGetBytePtr(pdfPageData.get()), CFDataGetLength(pdfPageData.get())), callbackID)); +} + +void WebPage::drawPagesToPDFImpl(uint64_t frameID, const PrintInfo& printInfo, uint32_t first, uint32_t count, RetainPtr<CFMutableDataRef>& pdfPageData) +{ + WebFrame* frame = WebProcess::singleton().webFrame(frameID); Frame* coreFrame = frame ? frame->coreFrame() : 0; - RetainPtr<CFMutableDataRef> pdfPageData = adoptCF(CFDataCreateMutable(0, 0)); + pdfPageData = adoptCF(CFDataCreateMutable(0, 0)); #if USE(CG) if (coreFrame) { -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) ASSERT(coreFrame->document()->printing() || pdfDocumentForPrintingFrame(coreFrame)); #else ASSERT(coreFrame->document()->printing()); @@ -3495,7 +4347,7 @@ void WebPage::drawPagesToPDF(uint64_t frameID, const PrintInfo& printInfo, uint3 CGRect mediaBox = (m_printContext && m_printContext->pageCount()) ? m_printContext->pageRect(0) : CGRectMake(0, 0, printInfo.availablePaperWidth, printInfo.availablePaperHeight); RetainPtr<CGContextRef> context = adoptCF(CGPDFContextCreate(pdfDataConsumer.get(), &mediaBox, 0)); -#if PLATFORM(MAC) && !PLATFORM(IOS) +#if PLATFORM(MAC) if (RetainPtr<PDFDocument> pdfDocument = pdfDocumentForPrintingFrame(coreFrame)) { ASSERT(!m_printContext); drawPagesToPDFFromPDFDocument(context.get(), pdfDocument.get(), printInfo, first, count); @@ -3521,8 +4373,6 @@ void WebPage::drawPagesToPDF(uint64_t frameID, const PrintInfo& printInfo, uint3 CGPDFContextClose(context.get()); } #endif - - send(Messages::WebPageProxy::DataCallback(IPC::DataReference(CFDataGetBytePtr(pdfPageData.get()), CFDataGetLength(pdfPageData.get())), callbackID)); } #elif PLATFORM(GTK) @@ -3549,18 +4399,59 @@ void WebPage::savePDFToFileInDownloadsFolder(const String& suggestedFilename, co send(Messages::WebPageProxy::SavePDFToFileInDownloadsFolder(suggestedFilename, originatingURLString, IPC::DataReference(data, size))); } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) void WebPage::savePDFToTemporaryFolderAndOpenWithNativeApplication(const String& suggestedFilename, const String& originatingURLString, const uint8_t* data, unsigned long size, const String& pdfUUID) { send(Messages::WebPageProxy::SavePDFToTemporaryFolderAndOpenWithNativeApplication(suggestedFilename, originatingURLString, IPC::DataReference(data, size), pdfUUID)); } #endif +void WebPage::addResourceRequest(unsigned long identifier, const WebCore::ResourceRequest& request) +{ + if (!request.url().protocolIsInHTTPFamily()) + return; + + if (m_mainFrameProgressCompleted && !ScriptController::processingUserGesture()) + return; + + ASSERT(!m_trackedNetworkResourceRequestIdentifiers.contains(identifier)); + bool wasEmpty = m_trackedNetworkResourceRequestIdentifiers.isEmpty(); + m_trackedNetworkResourceRequestIdentifiers.add(identifier); + if (wasEmpty) + send(Messages::WebPageProxy::SetNetworkRequestsInProgress(true)); +} + +void WebPage::removeResourceRequest(unsigned long identifier) +{ + if (!m_trackedNetworkResourceRequestIdentifiers.remove(identifier)) + return; + + if (m_trackedNetworkResourceRequestIdentifiers.isEmpty()) + send(Messages::WebPageProxy::SetNetworkRequestsInProgress(false)); +} + void WebPage::setMediaVolume(float volume) { m_page->setMediaVolume(volume); } +void WebPage::setMuted(MediaProducer::MutedStateFlags state) +{ + m_page->setMuted(state); +} + +#if ENABLE(MEDIA_SESSION) +void WebPage::handleMediaEvent(uint32_t eventType) +{ + m_page->handleMediaEvent(static_cast<MediaEventType>(eventType)); +} + +void WebPage::setVolumeOfMediaElement(double volume, uint64_t elementID) +{ + m_page->setVolumeOfMediaElement(volume, elementID); +} +#endif + void WebPage::setMayStartMediaWhenInWindow(bool mayStartMedia) { if (mayStartMedia == m_mayStartMediaWhenInWindow) @@ -3580,36 +4471,25 @@ void WebPage::runModal() m_isRunningModal = true; send(Messages::WebPageProxy::RunModal()); +#if !ASSERT_DISABLED + Ref<WebPage> protector(*this); +#endif RunLoop::run(); ASSERT(!m_isRunningModal); } -void WebPage::setMemoryCacheMessagesEnabled(bool memoryCacheMessagesEnabled) -{ - m_page->setMemoryCacheClientCallsEnabled(memoryCacheMessagesEnabled); -} - bool WebPage::canHandleRequest(const WebCore::ResourceRequest& request) { - if (SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(request.url().protocol())) + if (SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(request.url().protocol().toStringWithoutCopying())) return true; -#if ENABLE(BLOB) - if (request.url().protocolIs("blob")) + if (request.url().protocolIsBlob()) return true; -#endif return platformCanHandleRequest(request); } -#if USE(TILED_BACKING_STORE) -void WebPage::commitPageTransitionViewport() -{ - m_drawingArea->setLayerTreeStateIsFrozen(false); -} -#endif - -#if PLATFORM(MAC) +#if PLATFORM(COCOA) void WebPage::handleAlternativeTextUIResult(const String& result) { Frame& frame = m_page->focusController().focusedOrMainFrame(); @@ -3619,17 +4499,17 @@ void WebPage::handleAlternativeTextUIResult(const String& result) void WebPage::simulateMouseDown(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, double time) { - mouseEvent(WebMouseEvent(WebMouseEvent::MouseDown, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time)); + mouseEvent(WebMouseEvent(WebMouseEvent::MouseDown, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time, WebCore::ForceAtClick, WebMouseEvent::NoTap)); } void WebPage::simulateMouseUp(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, double time) { - mouseEvent(WebMouseEvent(WebMouseEvent::MouseUp, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time)); + mouseEvent(WebMouseEvent(WebMouseEvent::MouseUp, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time, WebCore::ForceAtClick, WebMouseEvent::NoTap)); } void WebPage::simulateMouseMotion(WebCore::IntPoint position, double time) { - mouseEvent(WebMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::NoButton, position, position, 0, 0, 0, 0, WebMouseEvent::Modifiers(), time)); + mouseEvent(WebMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::NoButton, position, position, 0, 0, 0, 0, WebMouseEvent::Modifiers(), time, 0, WebMouseEvent::NoTap)); } void WebPage::setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length) @@ -3660,12 +4540,12 @@ void WebPage::confirmCompositionForTesting(const String& compositionString) frame.editor().confirmComposition(compositionString); } -void WebPage::numWheelEventHandlersChanged(unsigned numWheelEventHandlers) +void WebPage::wheelEventHandlersChanged(bool hasHandlers) { - if (m_numWheelEventHandlers == numWheelEventHandlers) + if (m_hasWheelEventHandlers == hasHandlers) return; - m_numWheelEventHandlers = numWheelEventHandlers; + m_hasWheelEventHandlers = hasHandlers; recomputeShortCircuitHorizontalWheelEventsState(); } @@ -3708,7 +4588,7 @@ static bool pageContainsAnyHorizontalScrollbars(Frame* mainFrame) void WebPage::recomputeShortCircuitHorizontalWheelEventsState() { - bool canShortCircuitHorizontalWheelEvents = !m_numWheelEventHandlers; + bool canShortCircuitHorizontalWheelEvents = !m_hasWheelEventHandlers; if (canShortCircuitHorizontalWheelEvents) { // Check if we have any horizontal scroll bars on the page. @@ -3723,9 +4603,9 @@ void WebPage::recomputeShortCircuitHorizontalWheelEventsState() send(Messages::WebPageProxy::SetCanShortCircuitHorizontalWheelEvents(m_canShortCircuitHorizontalWheelEvents)); } -Frame* WebPage::mainFrame() const +MainFrame* WebPage::mainFrame() const { - return m_page ? &m_page->mainFrame() : 0; + return m_page ? &m_page->mainFrame() : nullptr; } FrameView* WebPage::mainFrameView() const @@ -3733,18 +4613,7 @@ FrameView* WebPage::mainFrameView() const if (Frame* frame = mainFrame()) return frame->view(); - return 0; -} - -void WebPage::setVisibilityStatePrerender() -{ - if (m_page) - m_page->setIsPrerender(); -} - -void WebPage::setIsVisuallyIdle(bool isVisuallyIdle) -{ - m_page->setIsVisuallyIdle(isVisuallyIdle); + return nullptr; } void WebPage::setScrollingPerformanceLoggingEnabled(bool enabled) @@ -3762,7 +4631,7 @@ bool WebPage::canPluginHandleResponse(const ResourceResponse& response) { #if ENABLE(NETSCAPE_PLUGIN_API) uint32_t pluginLoadPolicy; - bool allowOnlyApplicationPlugins = !m_mainFrame->coreFrame()->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin); + bool allowOnlyApplicationPlugins = !m_mainFrame->coreFrame()->loader().subframeLoader().allowPlugins(); uint64_t pluginProcessToken; String newMIMEType; @@ -3770,13 +4639,143 @@ bool WebPage::canPluginHandleResponse(const ResourceResponse& response) if (!sendSync(Messages::WebPageProxy::FindPlugin(response.mimeType(), PluginProcessTypeNormal, response.url().string(), response.url().string(), response.url().string(), allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription))) return false; - return pluginLoadPolicy != PluginModuleBlocked && pluginProcessToken; + bool isBlockedPlugin = (pluginLoadPolicy == PluginModuleBlockedForSecurity) || (pluginLoadPolicy == PluginModuleBlockedForCompatibility); + return !isBlockedPlugin && pluginProcessToken; #else UNUSED_PARAM(response); return false; #endif } +bool WebPage::shouldUseCustomContentProviderForResponse(const ResourceResponse& response) +{ + auto& mimeType = response.mimeType(); + if (mimeType.isNull()) + return false; + + // If a plug-in exists that claims to support this response, it should take precedence over the custom content provider. + // canPluginHandleResponse() is called last because it performs synchronous IPC. + return m_mimeTypesWithCustomContentProviders.contains(mimeType) && !canPluginHandleResponse(response); +} + +#if PLATFORM(COCOA) + +void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate) +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + + Ref<Frame> protector(frame); + + bool replacesText = false; + if (replacementEditingRange.location != notFound) { + RefPtr<Range> replacementRange = rangeFromEditingRange(frame, replacementEditingRange, static_cast<EditingRangeIsRelativeTo>(editingRangeIsRelativeTo)); + if (replacementRange) { + SetForScope<bool> isSelectingTextWhileInsertingAsynchronously(m_isSelectingTextWhileInsertingAsynchronously, suppressSelectionUpdate); + frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY)); + replacesText = true; + } + } + + if (registerUndoGroup) + send(Messages::WebPageProxy::RegisterInsertionUndoGrouping()); + + if (!frame.editor().hasComposition()) { + // An insertText: might be handled by other responders in the chain if we don't handle it. + // One example is space bar that results in scrolling down the page. + frame.editor().insertText(text, nullptr, replacesText ? TextEventInputAutocompletion : TextEventInputKeyboard); + } else + frame.editor().confirmComposition(text); +} + +void WebPage::getMarkedRangeAsync(uint64_t callbackID) +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + + RefPtr<Range> range = frame.editor().compositionRange(); + size_t location; + size_t length; + if (!range || !TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), location, length)) { + location = notFound; + length = 0; + } + + send(Messages::WebPageProxy::EditingRangeCallback(EditingRange(location, length), callbackID)); +} + +void WebPage::getSelectedRangeAsync(uint64_t callbackID) +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + + size_t location; + size_t length; + RefPtr<Range> range = frame.selection().toNormalizedRange(); + if (!range || !TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), location, length)) { + location = notFound; + length = 0; + } + + send(Messages::WebPageProxy::EditingRangeCallback(EditingRange(location, length), callbackID)); +} + +void WebPage::characterIndexForPointAsync(const WebCore::IntPoint& point, uint64_t callbackID) +{ + uint64_t index = notFound; + + HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(point); + Frame* frame = result.innerNonSharedNode() ? result.innerNodeFrame() : &m_page->focusController().focusedOrMainFrame(); + + RefPtr<Range> range = frame->rangeForPoint(result.roundedPointInInnerNodeFrame()); + if (range) { + size_t location; + size_t length; + if (TextIterator::getLocationAndLengthFromRange(frame->selection().rootEditableElementOrDocumentElement(), range.get(), location, length)) + index = static_cast<uint64_t>(location); + } + + send(Messages::WebPageProxy::UnsignedCallback(index, callbackID)); +} + +void WebPage::firstRectForCharacterRangeAsync(const EditingRange& editingRange, uint64_t callbackID) +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + IntRect result(IntPoint(0, 0), IntSize(0, 0)); + + RefPtr<Range> range = rangeFromEditingRange(frame, editingRange); + if (!range) { + send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, EditingRange(notFound, 0), callbackID)); + return; + } + + result = frame.view()->contentsToWindow(frame.editor().firstRectForRange(range.get())); + + // FIXME: Update actualRange to match the range of first rect. + send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, editingRange, callbackID)); +} + +void WebPage::setCompositionAsync(const String& text, Vector<CompositionUnderline> underlines, const EditingRange& selection, const EditingRange& replacementEditingRange) +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + + if (frame.selection().selection().isContentEditable()) { + RefPtr<Range> replacementRange; + if (replacementEditingRange.location != notFound) { + replacementRange = rangeFromEditingRange(frame, replacementEditingRange); + if (replacementRange) + frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY)); + } + + frame.editor().setComposition(text, underlines, selection.location, selection.location + selection.length); + } +} + +void WebPage::confirmCompositionAsync() +{ + Frame& frame = m_page->focusController().focusedOrMainFrame(); + frame.editor().confirmComposition(); +} + +#endif // PLATFORM(COCOA) + #if PLATFORM(GTK) static Frame* targetFrameForEditing(WebPage* page) { @@ -3784,17 +4783,16 @@ static Frame* targetFrameForEditing(WebPage* page) Editor& editor = targetFrame.editor(); if (!editor.canEdit()) - return 0; + return nullptr; if (editor.hasComposition()) { // We should verify the parent node of this IME composition node are // editable because JavaScript may delete a parent node of the composition // node. In this case, WebKit crashes while deleting texts from the parent // node, which doesn't exist any longer. - if (PassRefPtr<Range> range = editor.compositionRange()) { - Node* node = range->startContainer(); - if (!node || !node->isContentEditable()) - return 0; + if (auto range = editor.compositionRange()) { + if (!range->startContainer().isContentEditable()) + return nullptr; } } return &targetFrame; @@ -3815,37 +4813,39 @@ void WebPage::confirmComposition(const String& compositionString, int64_t select return; } - Element* scope = targetFrame->selection().rootEditableElement(); + Element* scope = targetFrame->selection().selection().rootEditableElement(); RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(scope, selectionStart, selectionLength); ASSERT_WITH_MESSAGE(selectionRange, "Invalid selection: [%lld:%lld] in text of length %d", static_cast<long long>(selectionStart), static_cast<long long>(selectionLength), scope->innerText().length()); if (selectionRange) { - VisibleSelection selection(selectionRange.get(), SEL_DEFAULT_AFFINITY); + VisibleSelection selection(*selectionRange, SEL_DEFAULT_AFFINITY); targetFrame->selection().setSelection(selection); } send(Messages::WebPageProxy::EditorStateChanged(editorState())); } -void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementStart, uint64_t replacementLength) +void WebPage::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, uint64_t selectionStart, uint64_t selectionLength, uint64_t replacementStart, uint64_t replacementLength) { Frame* targetFrame = targetFrameForEditing(this); - if (!targetFrame || !targetFrame->selection().isContentEditable()) { + if (!targetFrame || !targetFrame->selection().selection().isContentEditable()) { send(Messages::WebPageProxy::EditorStateChanged(editorState())); return; } + Ref<Frame> protector(*targetFrame); + if (replacementLength > 0) { // The layout needs to be uptodate before setting a selection targetFrame->document()->updateLayout(); - Element* scope = targetFrame->selection().rootEditableElement(); + Element* scope = targetFrame->selection().selection().rootEditableElement(); RefPtr<Range> replacementRange = TextIterator::rangeFromLocationAndLength(scope, replacementStart, replacementLength); targetFrame->editor().setIgnoreCompositionSelectionChange(true); - targetFrame->selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY)); + targetFrame->selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY)); targetFrame->editor().setIgnoreCompositionSelectionChange(false); } - targetFrame->editor().setComposition(text, underlines, selectionStart, selectionEnd); + targetFrame->editor().setComposition(text, underlines, selectionStart, selectionStart + selectionLength); send(Messages::WebPageProxy::EditorStateChanged(editorState())); } @@ -3857,14 +4857,179 @@ void WebPage::cancelComposition() } #endif +#if PLATFORM(MAC) +static bool needsHiddenContentEditableQuirk(bool needsQuirks, const URL& url) +{ + if (!needsQuirks) + return false; + + String host = url.host(); + String path = url.path(); + return equalLettersIgnoringASCIICase(host, "docs.google.com"); +} + +static bool needsPlainTextQuirk(bool needsQuirks, const URL& url) +{ + if (!needsQuirks) + return false; + + String host = url.host(); + + if (equalLettersIgnoringASCIICase(host, "twitter.com")) + return true; + + if (equalLettersIgnoringASCIICase(host, "onedrive.live.com")) + return true; + + String path = url.path(); + if (equalLettersIgnoringASCIICase(host, "www.icloud.com") && (path.contains("notes") || url.fragmentIdentifier().contains("notes"))) + return true; + + if (equalLettersIgnoringASCIICase(host, "trix-editor.org")) + return true; + + return false; +} +#endif + void WebPage::didChangeSelection() { + Frame& frame = m_page->focusController().focusedOrMainFrame(); + // The act of getting Dictionary Popup info can make selection changes that we should not propagate to the UIProcess. + // Specifically, if there is a caret selection, it will change to a range selection of the word around the caret. And + // then it will change back. + if (frame.editor().isGettingDictionaryPopupInfo()) + return; + + // Similarly, we don't want to propagate changes to the web process when inserting text asynchronously, since we will + // end up with a range selection very briefly right before inserting the text. + if (m_isSelectingTextWhileInsertingAsynchronously) + return; + + FrameView* view = frame.view(); + + // If there is a layout pending, we should avoid populating EditorState that require layout to be done or it will + // trigger a synchronous layout every time the selection changes. sendPostLayoutEditorStateIfNeeded() will be called + // to send the full editor state after layout is done if we send a partial editor state here. + auto editorState = this->editorState(view && view->needsLayout() ? IncludePostLayoutDataHint::No : IncludePostLayoutDataHint::Yes); + m_isEditorStateMissingPostLayoutData = editorState.isMissingPostLayoutData; + +#if PLATFORM(MAC) + bool hasPreviouslyFocusedDueToUserInteraction = m_hasEverFocusedElementDueToUserInteractionSincePageTransition; + m_hasEverFocusedElementDueToUserInteractionSincePageTransition |= m_userIsInteracting; + + if (!hasPreviouslyFocusedDueToUserInteraction && m_hasEverFocusedElementDueToUserInteractionSincePageTransition) { + if (needsHiddenContentEditableQuirk(m_page->settings().needsSiteSpecificQuirks(), m_page->mainFrame().document()->url())) { + m_needsHiddenContentEditableQuirk = true; + send(Messages::WebPageProxy::SetNeedsHiddenContentEditableQuirk(m_needsHiddenContentEditableQuirk)); + } + + if (needsPlainTextQuirk(m_page->settings().needsSiteSpecificQuirks(), m_page->mainFrame().document()->url())) { + m_needsPlainTextQuirk = true; + send(Messages::WebPageProxy::SetNeedsPlainTextQuirk(m_needsPlainTextQuirk)); + } + + send(Messages::WebPageProxy::SetHasHadSelectionChangesFromUserInteraction(m_hasEverFocusedElementDueToUserInteractionSincePageTransition)); + } + + // Abandon the current inline input session if selection changed for any other reason but an input method direct action. + // FIXME: This logic should be in WebCore. + // FIXME: Many changes that affect composition node do not go through didChangeSelection(). We need to do something when DOM manipulation affects the composition, because otherwise input method's idea about it will be different from Editor's. + // FIXME: We can't cancel composition when selection changes to NoSelection, but we probably should. + if (frame.editor().hasComposition() && !frame.editor().ignoreCompositionSelectionChange() && !frame.selection().isNone()) { + frame.editor().cancelComposition(); + discardedComposition(); + } else + send(Messages::WebPageProxy::EditorStateChanged(editorState)); +#else + send(Messages::WebPageProxy::EditorStateChanged(editorState), pageID(), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply); +#endif + +#if PLATFORM(IOS) + m_drawingArea->scheduleCompositingLayerFlush(); +#endif +} + +void WebPage::resetAssistedNodeForFrame(WebFrame* frame) +{ + if (!m_assistedNode) + return; + if (frame->isMainFrame() || m_assistedNode->document().frame() == frame->coreFrame()) { +#if PLATFORM(IOS) + send(Messages::WebPageProxy::StopAssistingNode()); +#elif PLATFORM(MAC) + send(Messages::WebPageProxy::SetEditableElementIsFocused(false)); +#endif + m_assistedNode = nullptr; + } +} + +void WebPage::elementDidFocus(WebCore::Node* node) +{ + if (m_assistedNode == node && m_isAssistingNodeDueToUserInteraction) + return; + + if (node->hasTagName(WebCore::HTMLNames::selectTag) || node->hasTagName(WebCore::HTMLNames::inputTag) || node->hasTagName(WebCore::HTMLNames::textareaTag) || node->hasEditableStyle()) { + m_assistedNode = node; + m_isAssistingNodeDueToUserInteraction |= m_userIsInteracting; + +#if PLATFORM(IOS) + AssistedNodeInformation information; + getAssistedNodeInformation(information); + RefPtr<API::Object> userData; + + m_formClient->willBeginInputSession(this, downcast<Element>(node), WebFrame::fromCoreFrame(*node->document().frame()), userData, m_userIsInteracting); + + send(Messages::WebPageProxy::StartAssistingNode(information, m_userIsInteracting, m_hasPendingBlurNotification, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get()))); +#elif PLATFORM(MAC) + if (node->hasTagName(WebCore::HTMLNames::selectTag)) + send(Messages::WebPageProxy::SetEditableElementIsFocused(false)); + else + send(Messages::WebPageProxy::SetEditableElementIsFocused(true)); +#endif + m_hasPendingBlurNotification = false; + } +} + +void WebPage::elementDidBlur(WebCore::Node* node) +{ + if (m_assistedNode == node) { + m_hasPendingBlurNotification = true; + RefPtr<WebPage> protectedThis(this); + callOnMainThread([protectedThis] { + if (protectedThis->m_hasPendingBlurNotification) { +#if PLATFORM(IOS) + protectedThis->send(Messages::WebPageProxy::StopAssistingNode()); +#elif PLATFORM(MAC) + protectedThis->send(Messages::WebPageProxy::SetEditableElementIsFocused(false)); +#endif + } + protectedThis->m_hasPendingBlurNotification = false; + }); + + m_isAssistingNodeDueToUserInteraction = false; + m_assistedNode = nullptr; + } +} + +void WebPage::sendPostLayoutEditorStateIfNeeded() +{ + if (!m_isEditorStateMissingPostLayoutData) + return; + + send(Messages::WebPageProxy::EditorStateChanged(editorState(IncludePostLayoutDataHint::Yes)), pageID(), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply); + m_isEditorStateMissingPostLayoutData = false; +} + +void WebPage::discardedComposition() +{ + send(Messages::WebPageProxy::CompositionWasCanceled()); send(Messages::WebPageProxy::EditorStateChanged(editorState())); } -void WebPage::setMainFrameInViewSourceMode(bool inViewSourceMode) +void WebPage::canceledComposition() { - m_mainFrame->coreFrame()->setInViewSourceMode(inViewSourceMode); + send(Messages::WebPageProxy::CompositionWasCanceled()); } void WebPage::setMinimumLayoutSize(const IntSize& minimumLayoutSize) @@ -3927,12 +5092,15 @@ bool WebPage::canShowMIMEType(const String& MIMEType) const if (MIMETypeRegistry::canShowMIMEType(MIMEType)) return true; + if (!MIMEType.isNull() && m_mimeTypesWithCustomContentProviders.contains(MIMEType)) + return true; + const PluginData& pluginData = m_page->pluginData(); - if (pluginData.supportsMimeType(MIMEType, PluginData::AllPlugins) && corePage()->mainFrame().loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin)) + if (pluginData.supportsWebVisibleMimeType(MIMEType, PluginData::AllPlugins) && corePage()->mainFrame().loader().subframeLoader().allowPlugins()) return true; // We can use application plugins even if plugins aren't enabled. - if (pluginData.supportsMimeType(MIMEType, PluginData::OnlyApplicationPlugins)) + if (pluginData.supportsWebVisibleMimeType(MIMEType, PluginData::OnlyApplicationPlugins)) return true; return false; @@ -3961,8 +5129,36 @@ void WebPage::didCancelCheckingText(uint64_t requestID) request->didCancel(); } +void WebPage::willReplaceMultipartContent(const WebFrame& frame) +{ +#if PLATFORM(IOS) + if (!frame.isMainFrame()) + return; + + m_previousExposedContentRect = m_drawingArea->exposedContentRect(); +#endif +} + +void WebPage::didReplaceMultipartContent(const WebFrame& frame) +{ +#if PLATFORM(IOS) + if (!frame.isMainFrame()) + return; + + // Restore the previous exposed content rect so that it remains fixed when replacing content + // from multipart/x-mixed-replace streams. + m_drawingArea->setExposedContentRect(m_previousExposedContentRect); +#endif +} + void WebPage::didCommitLoad(WebFrame* frame) { +#if PLATFORM(IOS) + frame->setFirstLayerTreeTransactionIDAfterDidCommitLoad(downcast<RemoteLayerTreeDrawingArea>(*m_drawingArea).nextTransactionID()); + cancelPotentialTapInFrame(*frame); +#endif + resetAssistedNodeForFrame(frame); + if (!frame->isMainFrame()) return; @@ -3972,17 +5168,56 @@ void WebPage::didCommitLoad(WebFrame* frame) reportUsedFeatures(); // Only restore the scale factor for standard frame loads (of the main frame). - if (frame->coreFrame()->loader().loadType() == FrameLoadTypeStandard) { + if (frame->coreFrame()->loader().loadType() == FrameLoadType::Standard) { Page* page = frame->coreFrame()->page(); + +#if PLATFORM(MAC) + // As a very special case, we disable non-default layout modes in WKView for main-frame PluginDocuments. + // Ideally we would only worry about this in WKView or the WKViewLayoutStrategies, but if we allow + // a round-trip to the UI process, you'll see the wrong scale temporarily. So, we reset it here, and then + // again later from the UI process. + if (frame->coreFrame()->document()->isPluginDocument()) { + scaleView(1); + setUseFixedLayout(false); + } +#endif + if (page && page->pageScaleFactor() != 1) scalePage(1, IntPoint()); } +#if PLATFORM(IOS) + m_hasReceivedVisibleContentRectsAfterDidCommitLoad = false; + m_scaleWasSetByUIProcess = false; + m_userHasChangedPageScaleFactor = false; + m_estimatedLatency = Seconds(1.0 / 60); + +#if ENABLE(IOS_TOUCH_EVENTS) + WebProcess::singleton().eventDispatcher().clearQueuedTouchEventsForPage(*this); +#endif + + resetViewportDefaultConfiguration(frame); + const Frame* coreFrame = frame->coreFrame(); + + bool viewportChanged = false; + if (m_viewportConfiguration.setContentsSize(coreFrame->view()->contentsSize())) + viewportChanged = true; + + if (m_viewportConfiguration.setViewportArguments(coreFrame->document()->viewportArguments())) + viewportChanged = true; + + if (viewportChanged) + viewportConfigurationChanged(); +#endif #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) resetPrimarySnapshottedPlugIn(); #endif - WebProcess::shared().updateActivePages(); +#if USE(OS_STATE) + m_loadCommitTime = std::chrono::system_clock::now(); +#endif + + WebProcess::singleton().updateActivePages(); updateMainFrameScrollOffsetPinning(); } @@ -4002,13 +5237,14 @@ void WebPage::didFinishLoad(WebFrame* frame) } #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) -static int primarySnapshottedPlugInSearchLimit = 3000; -static int primarySnapshottedPlugInSearchGap = 200; -static float primarySnapshottedPlugInSearchBucketSize = 1.1; -static int primarySnapshottedPlugInMinimumWidth = 400; -static int primarySnapshottedPlugInMinimumHeight = 300; -static unsigned maxPrimarySnapshottedPlugInDetectionAttempts = 2; -static int deferredPrimarySnapshottedPlugInDetectionDelay = 3; +static const int primarySnapshottedPlugInSearchLimit = 3000; +static const float primarySnapshottedPlugInSearchBucketSize = 1.1; +static const int primarySnapshottedPlugInMinimumWidth = 400; +static const int primarySnapshottedPlugInMinimumHeight = 300; +static const unsigned maxPrimarySnapshottedPlugInDetectionAttempts = 2; +static const int deferredPrimarySnapshottedPlugInDetectionDelay = 3; +static const float overlappingImageBoundsScale = 1.1; +static const float minimumOverlappingImageToPluginDimensionScale = .9; #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) void WebPage::determinePrimarySnapshottedPlugInTimerFired() @@ -4046,59 +5282,71 @@ void WebPage::determinePrimarySnapshottedPlugIn() ++m_numberOfPrimarySnapshotDetectionAttempts; - RenderView* renderView = corePage()->mainFrame().view()->renderView(); + layoutIfNeeded(); + + MainFrame& mainFrame = corePage()->mainFrame(); + if (!mainFrame.view()) + return; + if (!mainFrame.view()->renderView()) + return; + RenderView& mainRenderView = *mainFrame.view()->renderView(); IntRect searchRect = IntRect(IntPoint(), corePage()->mainFrame().view()->contentsSize()); searchRect.intersect(IntRect(IntPoint(), IntSize(primarySnapshottedPlugInSearchLimit, primarySnapshottedPlugInSearchLimit))); - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent); + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent); - HashSet<RenderObject*> seenRenderers; - HTMLPlugInImageElement* candidatePlugIn = 0; + HTMLPlugInImageElement* candidatePlugIn = nullptr; unsigned candidatePlugInArea = 0; - for (int x = searchRect.x(); x <= searchRect.width(); x += primarySnapshottedPlugInSearchGap) { - for (int y = searchRect.y(); y <= searchRect.height(); y += primarySnapshottedPlugInSearchGap) { - HitTestResult hitTestResult = HitTestResult(LayoutPoint(x, y)); - renderView->hitTest(request, hitTestResult); - - Element* element = hitTestResult.innerElement(); - if (!element) - continue; - - RenderObject* renderer = element->renderer(); - if (!renderer || !renderer->isBox()) - continue; - - RenderBox* renderBox = toRenderBox(renderer); - - if (!seenRenderers.add(renderer).isNewEntry) + for (Frame* frame = &mainFrame; frame; frame = frame->tree().traverseNextRendered()) { + if (!frame->loader().subframeLoader().containsPlugins()) + continue; + if (!frame->document() || !frame->view()) + continue; + for (auto& plugInImageElement : descendantsOfType<HTMLPlugInImageElement>(*frame->document())) { + if (plugInImageElement.displayState() == HTMLPlugInElement::Playing) continue; - if (!element->isPluginElement()) + auto pluginRenderer = plugInImageElement.renderer(); + if (!pluginRenderer || !pluginRenderer->isBox()) continue; - - HTMLPlugInElement* plugInElement = toHTMLPlugInElement(element); - if (!plugInElement->isPlugInImageElement()) + auto& pluginRenderBox = downcast<RenderBox>(*pluginRenderer); + if (!plugInIntersectsSearchRect(plugInImageElement)) continue; - HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(plugInElement); + IntRect plugInRectRelativeToView = plugInImageElement.clientRect(); + ScrollPosition scrollPosition = mainFrame.view()->documentScrollPositionRelativeToViewOrigin(); + IntRect plugInRectRelativeToTopDocument(plugInRectRelativeToView.location() + scrollPosition, plugInRectRelativeToView.size()); + HitTestResult hitTestResult(plugInRectRelativeToTopDocument.center()); + mainRenderView.hitTest(request, hitTestResult); - if (plugInElement->displayState() == HTMLPlugInElement::Playing) - continue; - - if (renderBox->contentWidth() < primarySnapshottedPlugInMinimumWidth || renderBox->contentHeight() < primarySnapshottedPlugInMinimumHeight) + Element* element = hitTestResult.targetElement(); + if (!element) continue; - LayoutUnit contentArea = renderBox->contentWidth() * renderBox->contentHeight(); - - if (contentArea > candidatePlugInArea * primarySnapshottedPlugInSearchBucketSize) { - candidatePlugIn = plugInImageElement; - candidatePlugInArea = contentArea; + IntRect elementRectRelativeToView = element->clientRect(); + IntRect elementRectRelativeToTopDocument(elementRectRelativeToView.location() + scrollPosition, elementRectRelativeToView.size()); + LayoutRect inflatedPluginRect = plugInRectRelativeToTopDocument; + LayoutUnit xOffset = (inflatedPluginRect.width() * overlappingImageBoundsScale - inflatedPluginRect.width()) / 2; + LayoutUnit yOffset = (inflatedPluginRect.height() * overlappingImageBoundsScale - inflatedPluginRect.height()) / 2; + inflatedPluginRect.inflateX(xOffset); + inflatedPluginRect.inflateY(yOffset); + + if (element != &plugInImageElement) { + if (!(is<HTMLImageElement>(*element) + && inflatedPluginRect.contains(elementRectRelativeToTopDocument) + && elementRectRelativeToTopDocument.width() > pluginRenderBox.width() * minimumOverlappingImageToPluginDimensionScale + && elementRectRelativeToTopDocument.height() > pluginRenderBox.height() * minimumOverlappingImageToPluginDimensionScale)) + continue; + LOG(Plugins, "Primary Plug-In Detection: Plug-in is hidden by an image that is roughly aligned with it, autoplaying regardless of whether or not it's actually the primary plug-in."); + plugInImageElement.restartSnapshottedPlugIn(); } + + if (plugInIsPrimarySize(plugInImageElement, candidatePlugInArea)) + candidatePlugIn = &plugInImageElement; } } - if (!candidatePlugIn) { LOG(Plugins, "Primary Plug-In Detection: fail - did not find a candidate plug-in."); if (m_numberOfPrimarySnapshotDetectionAttempts < maxPrimarySnapshottedPlugInDetectionAttempts) { @@ -4132,13 +5380,53 @@ bool WebPage::matchesPrimaryPlugIn(const String& pageOrigin, const String& plugi return (pageOrigin == m_primaryPlugInPageOrigin && pluginOrigin == m_primaryPlugInOrigin && mimeType == m_primaryPlugInMimeType); } + +bool WebPage::plugInIntersectsSearchRect(HTMLPlugInImageElement& plugInImageElement) +{ + MainFrame& mainFrame = corePage()->mainFrame(); + if (!mainFrame.view()) + return false; + if (!mainFrame.view()->renderView()) + return false; + + IntRect searchRect = IntRect(IntPoint(), corePage()->mainFrame().view()->contentsSize()); + searchRect.intersect(IntRect(IntPoint(), IntSize(primarySnapshottedPlugInSearchLimit, primarySnapshottedPlugInSearchLimit))); + + IntRect plugInRectRelativeToView = plugInImageElement.clientRect(); + if (plugInRectRelativeToView.isEmpty()) + return false; + ScrollPosition scrollPosition = mainFrame.view()->documentScrollPositionRelativeToViewOrigin(); + IntRect plugInRectRelativeToTopDocument(plugInRectRelativeToView.location() + toIntSize(scrollPosition), plugInRectRelativeToView.size()); + + return plugInRectRelativeToTopDocument.intersects(searchRect); +} + +bool WebPage::plugInIsPrimarySize(WebCore::HTMLPlugInImageElement& plugInImageElement, unsigned& candidatePlugInArea) +{ + auto* renderer = plugInImageElement.renderer(); + if (!is<RenderBox>(renderer)) + return false; + + auto& box = downcast<RenderBox>(*renderer); + if (box.contentWidth() < primarySnapshottedPlugInMinimumWidth || box.contentHeight() < primarySnapshottedPlugInMinimumHeight) + return false; + + LayoutUnit contentArea = box.contentWidth() * box.contentHeight(); + if (contentArea > candidatePlugInArea * primarySnapshottedPlugInSearchBucketSize) { + candidatePlugInArea = contentArea.toUnsigned(); + return true; + } + + return false; +} + #endif // ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC) -PassRefPtr<Range> WebPage::currentSelectionAsRange() +RefPtr<Range> WebPage::currentSelectionAsRange() { - Frame* frame = frameWithSelection(m_page.get()); + auto* frame = frameWithSelection(m_page.get()); if (!frame) - return 0; + return nullptr; return frame->selection().toNormalizedRange(); } @@ -4149,6 +5437,11 @@ void WebPage::reportUsedFeatures() m_loaderClient.featuresUsedInPage(this, namedFeatures); } +void WebPage::updateWebsitePolicies(const WebsitePolicies&) +{ + // FIXME: Update the website policies in m_page. +} + unsigned WebPage::extendIncrementalRenderingSuppression() { unsigned token = m_maximumRenderingSuppressionToken + 1; @@ -4177,13 +5470,241 @@ void WebPage::setScrollPinningBehavior(uint32_t pinning) m_page->mainFrame().view()->setScrollPinningBehavior(m_scrollPinningBehavior); } -PassRefPtr<DocumentLoader> WebPage::createDocumentLoader(Frame& frame, const ResourceRequest& request, const SubstituteData& substituteData) +void WebPage::setScrollbarOverlayStyle(std::optional<uint32_t> scrollbarStyle) { - RefPtr<WebDocumentLoader> documentLoader = WebDocumentLoader::create(request, substituteData); + if (scrollbarStyle) + m_scrollbarOverlayStyle = static_cast<ScrollbarOverlayStyle>(scrollbarStyle.value()); + else + m_scrollbarOverlayStyle = std::optional<ScrollbarOverlayStyle>(); + m_page->mainFrame().view()->recalculateScrollbarOverlayStyle(); +} + +Ref<DocumentLoader> WebPage::createDocumentLoader(Frame& frame, const ResourceRequest& request, const SubstituteData& substituteData) +{ + Ref<WebDocumentLoader> documentLoader = WebDocumentLoader::create(request, substituteData); + + if (frame.isMainFrame()) { + if (m_pendingNavigationID) { + documentLoader->setNavigationID(m_pendingNavigationID); + m_pendingNavigationID = 0; + } + } + + return WTFMove(documentLoader); +} + +void WebPage::updateCachedDocumentLoader(WebDocumentLoader& documentLoader, Frame& frame) +{ + if (m_pendingNavigationID && frame.isMainFrame()) { + documentLoader.setNavigationID(m_pendingNavigationID); + m_pendingNavigationID = 0; + } +} + +void WebPage::getBytecodeProfile(uint64_t callbackID) +{ + if (!commonVM().m_perBytecodeProfiler) { + send(Messages::WebPageProxy::StringCallback(String(), callbackID)); + return; + } - // FIXME: Set the navigation ID if possible. + String result = commonVM().m_perBytecodeProfiler->toJSON(); + ASSERT(result.length()); + send(Messages::WebPageProxy::StringCallback(result, callbackID)); +} - return documentLoader.release(); +void WebPage::getSamplingProfilerOutput(uint64_t callbackID) +{ +#if ENABLE(SAMPLING_PROFILER) + SamplingProfiler* samplingProfiler = commonVM().samplingProfiler(); + if (!samplingProfiler) { + send(Messages::WebPageProxy::InvalidateStringCallback(callbackID)); + return; + } + + StringPrintStream result; + samplingProfiler->reportTopFunctions(result); + samplingProfiler->reportTopBytecodes(result); + send(Messages::WebPageProxy::StringCallback(result.toString(), callbackID)); +#else + send(Messages::WebPageProxy::InvalidateStringCallback(callbackID)); +#endif +} + +RefPtr<WebCore::Range> WebPage::rangeFromEditingRange(WebCore::Frame& frame, const EditingRange& range, EditingRangeIsRelativeTo editingRangeIsRelativeTo) +{ + ASSERT(range.location != notFound); + + // Sanitize the input, because TextIterator::rangeFromLocationAndLength takes signed integers. + if (range.location > INT_MAX) + return 0; + int length; + if (range.length <= INT_MAX && range.location + range.length <= INT_MAX) + length = static_cast<int>(range.length); + else + length = INT_MAX - range.location; + + if (editingRangeIsRelativeTo == EditingRangeIsRelativeTo::EditableRoot) { + // Our critical assumption is that this code path is called by input methods that + // concentrate on a given area containing the selection. + // We have to do this because of text fields and textareas. The DOM for those is not + // directly in the document DOM, so serialization is problematic. Our solution is + // to use the root editable element of the selection start as the positional base. + // That fits with AppKit's idea of an input context. + return TextIterator::rangeFromLocationAndLength(frame.selection().rootEditableElementOrDocumentElement(), static_cast<int>(range.location), length); + } + + ASSERT(editingRangeIsRelativeTo == EditingRangeIsRelativeTo::Paragraph); + + const VisibleSelection& selection = frame.selection().selection(); + RefPtr<Range> selectedRange = selection.toNormalizedRange(); + if (!selectedRange) + return 0; + + RefPtr<Range> paragraphRange = makeRange(startOfParagraph(selection.visibleStart()), selection.visibleEnd()); + if (!paragraphRange) + return 0; + + ContainerNode& rootNode = paragraphRange.get()->startContainer().treeScope().rootNode(); + int paragraphStartIndex = TextIterator::rangeLength(Range::create(rootNode.document(), &rootNode, 0, ¶graphRange->startContainer(), paragraphRange->startOffset()).ptr()); + return TextIterator::rangeFromLocationAndLength(&rootNode, paragraphStartIndex + static_cast<int>(range.location), length); +} + +void WebPage::didChangeScrollOffsetForFrame(Frame* frame) +{ + if (!frame->isMainFrame()) + return; + + // If this is called when tearing down a FrameView, the WebCore::Frame's + // current FrameView will be null. + if (!frame->view()) + return; + + updateMainFrameScrollOffsetPinning(); +} + +void WebPage::postMessage(const String& messageName, API::Object* messageBody) +{ + send(Messages::WebPageProxy::HandleMessage(messageName, UserData(WebProcess::singleton().transformObjectsToHandles(messageBody)))); +} + +void WebPage::postSynchronousMessageForTesting(const String& messageName, API::Object* messageBody, RefPtr<API::Object>& returnData) +{ + UserData returnUserData; + + auto& webProcess = WebProcess::singleton(); + if (!sendSync(Messages::WebPageProxy::HandleSynchronousMessage(messageName, UserData(webProcess.transformObjectsToHandles(messageBody))), Messages::WebPageProxy::HandleSynchronousMessage::Reply(returnUserData), Seconds::infinity(), IPC::SendSyncOption::UseFullySynchronousModeForTesting)) + returnData = nullptr; + else + returnData = webProcess.transformHandlesToObjects(returnUserData.object()); +} + +void WebPage::clearWheelEventTestTrigger() +{ + if (!m_page) + return; + + m_page->clearTrigger(); +} + +void WebPage::setShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument) +{ + if (!m_drawingArea) + return; + + m_drawingArea->setShouldScaleViewToFitDocument(shouldScaleViewToFitDocument); +} + +void WebPage::imageOrMediaDocumentSizeChanged(const IntSize& newSize) +{ + send(Messages::WebPageProxy::ImageOrMediaDocumentSizeChanged(newSize)); +} + +void WebPage::addUserScript(const String& source, WebCore::UserContentInjectedFrames injectedFrames, WebCore::UserScriptInjectionTime injectionTime) +{ + WebCore::UserScript userScript{ source, WebCore::blankURL(), Vector<String>(), Vector<String>(), injectionTime, injectedFrames }; + + m_userContentController->addUserScript(*InjectedBundleScriptWorld::normalWorld(), WTFMove(userScript)); +} + +void WebPage::addUserStyleSheet(const String& source, WebCore::UserContentInjectedFrames injectedFrames) +{ + WebCore::UserStyleSheet userStyleSheet{ source, WebCore::blankURL(), Vector<String>(), Vector<String>(), injectedFrames, UserStyleUserLevel }; + + m_userContentController->addUserStyleSheet(*InjectedBundleScriptWorld::normalWorld(), WTFMove(userStyleSheet)); +} + +void WebPage::removeAllUserContent() +{ + m_userContentController->removeAllUserContent(); +} + +void WebPage::dispatchDidReachLayoutMilestone(WebCore::LayoutMilestones milestones) +{ + RefPtr<API::Object> userData; + injectedBundleLoaderClient().didReachLayoutMilestone(this, milestones, userData); + + // Clients should not set userData for this message, and it won't be passed through. + ASSERT(!userData); + + // The drawing area might want to defer dispatch of didLayout to the UI process. + if (m_drawingArea && m_drawingArea->dispatchDidReachLayoutMilestone(milestones)) + return; + + send(Messages::WebPageProxy::DidReachLayoutMilestone(milestones)); +} + +void WebPage::didRestoreScrollPosition() +{ + send(Messages::WebPageProxy::DidRestoreScrollPosition()); +} + +void WebPage::setResourceCachingDisabled(bool disabled) +{ + m_page->setResourceCachingDisabled(disabled); +} + +void WebPage::setUserInterfaceLayoutDirection(uint32_t direction) +{ + m_userInterfaceLayoutDirection = static_cast<WebCore::UserInterfaceLayoutDirection>(direction); + m_page->setUserInterfaceLayoutDirection(m_userInterfaceLayoutDirection); +} + +#if ENABLE(GAMEPAD) + +void WebPage::gamepadActivity(const Vector<GamepadData>& gamepadDatas, bool shouldMakeGamepadsVisible) +{ + WebGamepadProvider::singleton().gamepadActivity(gamepadDatas, shouldMakeGamepadsVisible); +} + +#endif + +#if ENABLE(POINTER_LOCK) +void WebPage::didAcquirePointerLock() +{ + corePage()->pointerLockController().didAcquirePointerLock(); +} + +void WebPage::didNotAcquirePointerLock() +{ + corePage()->pointerLockController().didNotAcquirePointerLock(); +} + +void WebPage::didLosePointerLock() +{ + corePage()->pointerLockController().didLosePointerLock(); +} +#endif + +void WebPage::didGetLoadDecisionForIcon(bool decision, uint64_t loadIdentifier, uint64_t newCallbackID) +{ + if (auto* documentLoader = corePage()->mainFrame().loader().documentLoader()) + documentLoader->didGetLoadDecisionForIcon(decision, loadIdentifier, newCallbackID); +} + +void WebPage::setUseIconLoadingClient(bool useIconLoadingClient) +{ + static_cast<WebFrameLoaderClient&>(corePage()->mainFrame().loader().client()).setUseIconLoadingClient(useIconLoadingClient); } } // namespace WebKit |