diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/page/Page.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/page/Page.cpp')
-rw-r--r-- | Source/WebCore/page/Page.cpp | 1395 |
1 files changed, 1035 insertions, 360 deletions
diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index d5d994919..1fd0aad74 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2006-2015 Apple Inc. All Rights Reserved. * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -20,25 +20,29 @@ #include "config.h" #include "Page.h" +#include "ActivityStateChangeObserver.h" #include "AlternativeTextClient.h" -#include "AnimationController.h" +#include "ApplicationCacheStorage.h" #include "BackForwardClient.h" #include "BackForwardController.h" +#include "CSSAnimationController.h" #include "Chrome.h" #include "ChromeClient.h" #include "ClientRectList.h" #include "ContextMenuClient.h" #include "ContextMenuController.h" -#include "DOMWindow.h" +#include "DatabaseProvider.h" +#include "DiagnosticLoggingClient.h" +#include "DiagnosticLoggingKeys.h" +#include "DocumentLoader.h" #include "DocumentMarkerController.h" -#include "DocumentStyleSheetCollection.h" #include "DragController.h" #include "Editor.h" #include "EditorClient.h" +#include "EmptyClients.h" #include "Event.h" #include "EventNames.h" -#include "ExceptionCode.h" -#include "ExceptionCodePlaceholder.h" +#include "ExtensionStyleSheets.h" #include "FileSystem.h" #include "FocusController.h" #include "FrameLoader.h" @@ -51,104 +55,159 @@ #include "HistoryItem.h" #include "InspectorController.h" #include "InspectorInstrumentation.h" +#include "LibWebRTCProvider.h" #include "Logging.h" #include "MainFrame.h" #include "MediaCanStartListener.h" #include "Navigator.h" #include "NetworkStateNotifier.h" -#include "PageActivityAssertionToken.h" #include "PageCache.h" -#include "PageConsole.h" +#include "PageConfiguration.h" +#include "PageConsoleClient.h" #include "PageDebuggable.h" #include "PageGroup.h" -#include "PageThrottler.h" +#include "PageOverlayController.h" +#include "PerformanceMonitor.h" +#include "PlatformMediaSessionManager.h" #include "PlugInClient.h" #include "PluginData.h" -#include "PluginView.h" +#include "PluginInfoProvider.h" +#include "PluginViewBase.h" #include "PointerLockController.h" #include "ProgressTracker.h" #include "RenderLayerCompositor.h" #include "RenderTheme.h" #include "RenderView.h" #include "RenderWidget.h" +#include "ResourceUsageOverlay.h" #include "RuntimeEnabledFeatures.h" +#include "SVGDocumentExtensions.h" #include "SchemeRegistry.h" #include "ScriptController.h" #include "ScrollingCoordinator.h" #include "Settings.h" #include "SharedBuffer.h" +#include "SocketProvider.h" #include "StorageArea.h" #include "StorageNamespace.h" +#include "StorageNamespaceProvider.h" #include "StyleResolver.h" +#include "StyleScope.h" #include "SubframeLoader.h" #include "TextResourceDecoder.h" -#include "UserContentController.h" +#include "UserContentProvider.h" +#include "UserInputBridge.h" +#include "ValidationMessageClient.h" #include "VisitedLinkState.h" +#include "VisitedLinkStore.h" #include "VoidCallback.h" +#include "WebGLStateTracker.h" #include "Widget.h" -#include <wtf/HashMap.h> +#include <wtf/CurrentTime.h> #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> #include <wtf/text/Base64.h> #include <wtf/text/StringHash.h> +#if ENABLE(WEB_REPLAY) +#include "ReplayController.h" +#include <replay/InputCursor.h> +#endif + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) +#include "HTMLVideoElement.h" +#include "MediaPlaybackTarget.h" +#endif + +#if ENABLE(MEDIA_SESSION) +#include "MediaSessionManager.h" +#endif + +#if ENABLE(INDEXED_DATABASE) +#include "IDBConnectionToServer.h" +#include "InProcessIDBServer.h" +#endif + +#if ENABLE(DATA_INTERACTION) +#include "SelectionRect.h" +#endif + namespace WebCore { static HashSet<Page*>* allPages; +static unsigned nonUtilityPageCount { 0 }; + +static inline bool isUtilityPageChromeClient(ChromeClient& chromeClient) +{ + return chromeClient.isEmptyChromeClient() || chromeClient.isSVGImageChromeClient(); +} DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page")); +void Page::forEachPage(std::function<void(Page&)> function) +{ + if (!allPages) + return; + for (Page* page : *allPages) + function(*page); +} + +void Page::updateValidationBubbleStateIfNeeded() +{ + if (auto* client = validationMessageClient()) + client->updateValidationBubbleStateIfNeeded(); +} + static void networkStateChanged(bool isOnLine) { Vector<Ref<Frame>> frames; // Get all the frames of all the pages in all the page groups - for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) { - for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) + for (auto& page : *allPages) { + for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) frames.append(*frame); - InspectorInstrumentation::networkStateChanged(*it); + InspectorInstrumentation::networkStateChanged(*page); } AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent; - for (unsigned i = 0; i < frames.size(); i++) - frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false)); + for (auto& frame : frames) { + if (!frame->document()) + continue; + frame->document()->dispatchWindowEvent(Event::create(eventName, false, false)); + } } -float deviceScaleFactor(Frame* frame) -{ - if (!frame) - return 1; - Page* page = frame->page(); - if (!page) - return 1; - return page->deviceScaleFactor(); -} +static const ActivityState::Flags PageInitialActivityState = ActivityState::IsVisible | ActivityState::IsInWindow; -Page::Page(PageClients& pageClients) - : m_chrome(std::make_unique<Chrome>(*this, *pageClients.chromeClient)) +Page::Page(PageConfiguration&& pageConfiguration) + : m_chrome(std::make_unique<Chrome>(*this, *pageConfiguration.chromeClient)) , m_dragCaretController(std::make_unique<DragCaretController>()) #if ENABLE(DRAG_SUPPORT) - , m_dragController(std::make_unique<DragController>(*this, *pageClients.dragClient)) + , m_dragController(std::make_unique<DragController>(*this, *pageConfiguration.dragClient)) #endif - , m_focusController(std::make_unique<FocusController>(*this)) + , m_focusController(std::make_unique<FocusController>(*this, PageInitialActivityState)) #if ENABLE(CONTEXT_MENUS) - , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageClients.contextMenuClient)) + , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageConfiguration.contextMenuClient)) #endif -#if ENABLE(INSPECTOR) - , m_inspectorController(std::make_unique<InspectorController>(*this, pageClients.inspectorClient)) + , m_userInputBridge(std::make_unique<UserInputBridge>(*this)) +#if ENABLE(WEB_REPLAY) + , m_replayController(std::make_unique<ReplayController>(*this)) #endif + , m_inspectorController(std::make_unique<InspectorController>(*this, pageConfiguration.inspectorClient)) #if ENABLE(POINTER_LOCK) - , m_pointerLockController(PointerLockController::create(this)) + , m_pointerLockController(std::make_unique<PointerLockController>(*this)) #endif , m_settings(Settings::create(this)) - , m_progress(std::make_unique<ProgressTracker>(*pageClients.progressTrackerClient)) - , m_backForwardController(std::make_unique<BackForwardController>(*this, pageClients.backForwardClient)) - , m_mainFrame(MainFrame::create(*this, *pageClients.loaderClientForMainFrame)) + , m_progress(std::make_unique<ProgressTracker>(*pageConfiguration.progressTrackerClient)) + , m_backForwardController(std::make_unique<BackForwardController>(*this, *WTFMove(pageConfiguration.backForwardClient))) + , m_mainFrame(MainFrame::create(*this, pageConfiguration)) , m_theme(RenderTheme::themeForPage(this)) - , m_editorClient(pageClients.editorClient) - , m_plugInClient(pageClients.plugInClient) - , m_validationMessageClient(pageClients.validationMessageClient) - , m_subframeCount(0) + , m_editorClient(WTFMove(pageConfiguration.editorClient)) + , m_plugInClient(pageConfiguration.plugInClient) + , m_validationMessageClient(WTFMove(pageConfiguration.validationMessageClient)) + , m_diagnosticLoggingClient(WTFMove(pageConfiguration.diagnosticLoggingClient)) + , m_webGLStateTracker(WTFMove(pageConfiguration.webGLStateTracker)) + , m_libWebRTCProvider(WTFMove(pageConfiguration.libWebRTCProvider)) , m_openedByDOM(false) , m_tabKeyCyclesThroughElements(true) , m_defersLoading(false) @@ -157,24 +216,27 @@ Page::Page(PageClients& pageClients) , m_areMemoryCacheClientCallsEnabled(true) , m_mediaVolume(1) , m_pageScaleFactor(1) - , m_deviceScaleFactor(1) + , m_zoomedOutPageScaleFactor(0) + , m_topContentInset(0) +#if ENABLE(TEXT_AUTOSIZING) + , m_textAutosizingWidth(0) +#endif , m_suppressScrollbarAnimations(false) + , m_verticalScrollElasticity(ScrollElasticityAllowed) + , m_horizontalScrollElasticity(ScrollElasticityAllowed) , m_didLoadUserStyleSheet(false) , m_userStyleSheetModificationTime(0) - , m_group(0) - , m_debugger(0) - , m_customHTMLTokenizerTimeDelay(-1) - , m_customHTMLTokenizerChunkSize(-1) + , m_group(nullptr) + , m_debugger(nullptr) , m_canStartMedia(true) #if ENABLE(VIEW_MODE_CSS_MEDIA) , m_viewMode(ViewModeWindowed) #endif // ENABLE(VIEW_MODE_CSS_MEDIA) - , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval()) - , m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()) + , m_timerAlignmentInterval(DOMTimer::defaultAlignmentInterval()) + , m_timerAlignmentIntervalIncreaseTimer(*this, &Page::timerAlignmentIntervalIncreaseTimerFired) , m_isEditable(false) - , m_isInWindow(true) - , m_isVisible(true) , m_isPrerender(false) + , m_activityState(PageInitialActivityState) , m_requestedLayoutMilestones(0) , m_headerHeight(0) , m_footerHeight(0) @@ -182,17 +244,32 @@ Page::Page(PageClients& pageClients) #ifndef NDEBUG , m_isPainting(false) #endif - , m_alternativeTextClient(pageClients.alternativeTextClient) + , m_alternativeTextClient(pageConfiguration.alternativeTextClient) , m_scriptedAnimationsSuspended(false) - , m_pageThrottler(std::make_unique<PageThrottler>(*this)) - , m_console(std::make_unique<PageConsole>(*this)) + , m_consoleClient(std::make_unique<PageConsoleClient>(*this)) #if ENABLE(REMOTE_INSPECTOR) , m_inspectorDebuggable(std::make_unique<PageDebuggable>(*this)) #endif , m_lastSpatialNavigationCandidatesCount(0) // NOTE: Only called from Internals for Spatial Navigation testing. - , m_framesHandlingBeforeUnloadEvent(0) -{ - ASSERT(m_editorClient); + , m_forbidPromptsDepth(0) + , m_socketProvider(WTFMove(pageConfiguration.socketProvider)) + , m_applicationCacheStorage(*WTFMove(pageConfiguration.applicationCacheStorage)) + , m_databaseProvider(*WTFMove(pageConfiguration.databaseProvider)) + , m_pluginInfoProvider(*WTFMove(pageConfiguration.pluginInfoProvider)) + , m_storageNamespaceProvider(*WTFMove(pageConfiguration.storageNamespaceProvider)) + , m_userContentProvider(*WTFMove(pageConfiguration.userContentProvider)) + , m_visitedLinkStore(*WTFMove(pageConfiguration.visitedLinkStore)) + , m_sessionID(SessionID::defaultSessionID()) + , m_isClosing(false) + , m_isUtilityPage(isUtilityPageChromeClient(chrome().client())) + , m_performanceMonitor(isUtilityPage() ? nullptr : std::make_unique<PerformanceMonitor>(*this)) +{ + updateTimerThrottlingState(); + + m_pluginInfoProvider->addPage(*this); + m_storageNamespaceProvider->addPage(*this); + m_userContentProvider->addPage(*this); + m_visitedLinkStore->addPage(*this); if (!allPages) { allPages = new HashSet<Page*>; @@ -202,6 +279,8 @@ Page::Page(PageClients& pageClients) ASSERT(!allPages->contains(this)); allPages->add(this); + if (!isUtilityPage()) + ++nonUtilityPageCount; #ifndef NDEBUG pageCounter.increment(); @@ -210,42 +289,67 @@ Page::Page(PageClients& pageClients) #if ENABLE(REMOTE_INSPECTOR) m_inspectorDebuggable->init(); #endif + +#if PLATFORM(COCOA) + platformInitialize(); +#endif } Page::~Page() { - m_mainFrame->setView(0); + ASSERT(!m_nestedRunLoopCount); + ASSERT(!m_unnestCallback); + + m_validationMessageClient = nullptr; + m_diagnosticLoggingClient = nullptr; + m_mainFrame->setView(nullptr); setGroupName(String()); allPages->remove(this); + if (!isUtilityPage()) + --nonUtilityPageCount; m_settings->pageDestroyed(); + m_inspectorController->inspectedPageDestroyed(); + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { frame->willDetachPage(); frame->detachFromPage(); } - m_editorClient->pageDestroyed(); if (m_plugInClient) m_plugInClient->pageDestroyed(); if (m_alternativeTextClient) m_alternativeTextClient->pageDestroyed(); -#if ENABLE(INSPECTOR) - m_inspectorController->inspectedPageDestroyed(); -#endif - if (m_scrollingCoordinator) m_scrollingCoordinator->pageDestroyed(); backForward().close(); + PageCache::singleton().removeAllItemsForPage(*this); #ifndef NDEBUG pageCounter.decrement(); #endif - if (m_userContentController) - m_userContentController->removePage(*this); + m_pluginInfoProvider->removePage(*this); + m_storageNamespaceProvider->removePage(*this); + m_userContentProvider->removePage(*this); + m_visitedLinkStore->removePage(*this); +} + +void Page::clearPreviousItemFromAllPages(HistoryItem* item) +{ + if (!allPages) + return; + + for (auto& page : *allPages) { + HistoryController& controller = page->mainFrame().loader().history(); + if (item == controller.previousItem()) { + controller.clearPreviousItem(); + return; + } + } } uint64_t Page::renderTreeSize() const @@ -267,7 +371,7 @@ ViewportArguments Page::viewportArguments() const ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { - m_scrollingCoordinator = chrome().client().createScrollingCoordinator(this); + m_scrollingCoordinator = chrome().client().createScrollingCoordinator(*this); if (!m_scrollingCoordinator) m_scrollingCoordinator = ScrollingCoordinator::create(this); } @@ -297,18 +401,22 @@ String Page::synchronousScrollingReasonsAsText() return String(); } -PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame) +Ref<ClientRectList> Page::nonFastScrollableRects() { if (Document* document = m_mainFrame->document()) document->updateLayout(); Vector<IntRect> rects; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects(); + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) { + const EventTrackingRegions& eventTrackingRegions = scrollingCoordinator->absoluteEventTrackingRegions(); + for (const auto& synchronousEventRegion : eventTrackingRegions.eventSpecificSynchronousDispatchRegions) + rects.appendVector(synchronousEventRegion.value.rects()); + } Vector<FloatQuad> quads(rects.size()); for (size_t i = 0; i < rects.size(); ++i) quads[i] = FloatRect(rects[i]); + return ClientRectList::create(quads); } @@ -318,7 +426,7 @@ struct ViewModeInfo { Page::ViewMode type; }; static const int viewModeMapSize = 5; -static ViewModeInfo viewModeMap[viewModeMapSize] = { +static const ViewModeInfo viewModeMap[viewModeMapSize] = { {"windowed", Page::ViewModeWindowed}, {"floating", Page::ViewModeFloating}, {"fullscreen", Page::ViewModeFullscreen}, @@ -328,9 +436,9 @@ static ViewModeInfo viewModeMap[viewModeMapSize] = { Page::ViewMode Page::stringToViewMode(const String& text) { - for (int i = 0; i < viewModeMapSize; ++i) { - if (text == viewModeMap[i].name) - return viewModeMap[i].type; + for (auto& mode : viewModeMap) { + if (text == mode.name) + return mode.type; } return Page::ViewModeInvalid; } @@ -342,14 +450,12 @@ void Page::setViewMode(ViewMode viewMode) m_viewMode = viewMode; - if (!m_mainFrame) - return; if (m_mainFrame->view()) m_mainFrame->view()->forceLayout(); if (m_mainFrame->document()) - m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately); + m_mainFrame->document()->styleScope().didChangeStyleSheetEnvironment(); } #endif // ENABLE(VIEW_MODE_CSS_MEDIA) @@ -363,11 +469,11 @@ void Page::setOpenedByDOM() m_openedByDOM = true; } -void Page::goToItem(HistoryItem* item, FrameLoadType type) +void Page::goToItem(HistoryItem& item, FrameLoadType type) { // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later. - RefPtr<HistoryItem> protector(item); + Ref<HistoryItem> protector(item); if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item)) m_mainFrame->loader().stopAllLoaders(); @@ -409,37 +515,26 @@ void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment() { if (!allPages) return; - HashSet<Page*>::iterator end = allPages->end(); - for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) - for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) { + for (auto& page : *allPages) { + for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) { // If a change in the global environment has occurred, we need to // make sure all the properties a recomputed, therefore we invalidate // the properties cache. - if (StyleResolver* styleResolver = frame->document()->styleResolverIfExists()) + if (!frame->document()) + continue; + if (StyleResolver* styleResolver = frame->document()->styleScope().resolverIfExists()) styleResolver->invalidateMatchedPropertiesCache(); frame->document()->scheduleForcedStyleRecalc(); } + } } void Page::setNeedsRecalcStyleInAllFrames() { + // FIXME: Figure out what this function is actually trying to add in different call sites. for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { if (Document* document = frame->document()) - document->styleResolverChanged(DeferRecalcStyle); - } -} - -void Page::jettisonStyleResolversInAllDocuments() -{ - if (!allPages) - return; - - for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) { - Page& page = **it; - for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) { - if (Document* document = frame->document()) - document->clearStyleResolver(); - } + document->styleScope().didChangeStyleSheetEnvironment(); } } @@ -448,41 +543,47 @@ void Page::refreshPlugins(bool reload) if (!allPages) return; - PluginData::refresh(); + HashSet<PluginInfoProvider*> pluginInfoProviders; - Vector<Ref<Frame>> framesNeedingReload; + for (auto& page : *allPages) + pluginInfoProviders.add(&page->pluginInfoProvider()); - for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) { - Page& page = **it; - page.m_pluginData.clear(); - - if (!reload) - continue; - - for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) { - if (frame->loader().subframeLoader().containsPlugins()) - framesNeedingReload.append(*frame); - } - } - - for (size_t i = 0; i < framesNeedingReload.size(); ++i) - framesNeedingReload[i]->loader().reload(); + for (auto& pluginInfoProvider : pluginInfoProviders) + pluginInfoProvider->refresh(reload); } -PluginData& Page::pluginData() const +PluginData& Page::pluginData() { if (!m_pluginData) - m_pluginData = PluginData::create(this); + m_pluginData = PluginData::create(*this); return *m_pluginData; } -inline MediaCanStartListener* Page::takeAnyMediaCanStartListener() +void Page::clearPluginData() +{ + m_pluginData = nullptr; +} + +bool Page::showAllPlugins() const +{ + if (m_showAllPlugins) + return true; + + if (Document* document = mainFrame().document()) + return document->securityOrigin().isLocal(); + + return false; +} + +inline std::optional<std::pair<MediaCanStartListener&, Document&>> Page::takeAnyMediaCanStartListener() { for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener()) - return listener; + return { { *listener, *frame->document() } }; } - return 0; + return std::nullopt; } void Page::setCanStartMedia(bool canStartMedia) @@ -493,10 +594,10 @@ void Page::setCanStartMedia(bool canStartMedia) m_canStartMedia = canStartMedia; while (m_canStartMedia) { - MediaCanStartListener* listener = takeAnyMediaCanStartListener(); + auto listener = takeAnyMediaCanStartListener(); if (!listener) break; - listener->mediaCanStart(); + listener->first.mediaCanStart(listener->second); } } @@ -536,35 +637,37 @@ bool Page::findString(const String& target, FindOptions options) return false; } -void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>* matchRanges, int& indexForSelection) +void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>& matchRanges, int& indexForSelection) { indexForSelection = 0; Frame* frame = &mainFrame(); - Frame* frameWithSelection = 0; + Frame* frameWithSelection = nullptr; do { - frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges); + frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges.size()) : 0, true, &matchRanges); if (frame->selection().isRange()) frameWithSelection = frame; frame = incrementFrame(frame, true, false); } while (frame); - if (matchRanges->isEmpty()) + if (matchRanges.isEmpty()) return; if (frameWithSelection) { indexForSelection = NoMatchAfterUserSelection; RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange(); if (options & Backwards) { - for (size_t i = matchRanges->size(); i > 0; --i) { - if (selectedRange->compareBoundaryPoints(Range::END_TO_START, matchRanges->at(i - 1).get(), IGNORE_EXCEPTION) > 0) { + for (size_t i = matchRanges.size(); i > 0; --i) { + auto result = selectedRange->compareBoundaryPoints(Range::END_TO_START, *matchRanges[i - 1]); + if (!result.hasException() && result.releaseReturnValue() > 0) { indexForSelection = i - 1; break; } } } else { - for (size_t i = 0; i < matchRanges->size(); ++i) { - if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), IGNORE_EXCEPTION) < 0) { + for (size_t i = 0, size = matchRanges.size(); i < size; ++i) { + auto result = selectedRange->compareBoundaryPoints(Range::START_TO_END, *matchRanges[i]); + if (!result.hasException() && result.releaseReturnValue() < 0) { indexForSelection = i; break; } @@ -572,26 +675,26 @@ void Page::findStringMatchingRanges(const String& target, FindOptions options, i } } else { if (options & Backwards) - indexForSelection = matchRanges->size() - 1; + indexForSelection = matchRanges.size() - 1; else indexForSelection = 0; } } -PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options) +RefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options) { if (target.isEmpty()) - return 0; + return nullptr; if (referenceRange && referenceRange->ownerDocument().page() != this) - return 0; + return nullptr; bool shouldWrap = options & WrapAround; Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame(); Frame* startFrame = frame; do { if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround)) - return resultRange.release(); + return resultRange; frame = incrementFrame(frame, !(options & Backwards), shouldWrap); } while (frame && frame != startFrame); @@ -600,10 +703,10 @@ PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRang // We cheat a bit and just search again with wrap on. if (shouldWrap && referenceRange) { if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection)) - return resultRange.release(); + return resultRange; } - return 0; + return nullptr; } unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches) @@ -685,6 +788,13 @@ void Page::setInLowQualityImageInterpolationMode(bool mode) m_inLowQualityInterpolationMode = mode; } +DiagnosticLoggingClient& Page::diagnosticLoggingClient() const +{ + if (!settings().diagnosticLoggingEnabled() || !m_diagnosticLoggingClient) + return emptyDiagnosticLoggingClient(); + return *m_diagnosticLoggingClient; +} + void Page::setMediaVolume(float volume) { if (volume < 0 || volume > 1) @@ -695,21 +805,47 @@ void Page::setMediaVolume(float volume) m_mediaVolume = volume; for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; frame->document()->mediaVolumeDidChange(); } } -void Page::setPageScaleFactor(float scale, const IntPoint& origin) +void Page::setZoomedOutPageScaleFactor(float scale) +{ + if (m_zoomedOutPageScaleFactor == scale) + return; + m_zoomedOutPageScaleFactor = scale; + + mainFrame().deviceOrPageScaleFactorChanged(); +} + +void Page::setPageScaleFactor(float scale, const IntPoint& origin, bool inStableState) { Document* document = mainFrame().document(); FrameView* view = document->view(); if (scale == m_pageScaleFactor) { - if (view && (view->scrollPosition() != origin || view->delegatesScrolling())) { + if (view && view->scrollPosition() != origin) { if (!m_settings->delegatesPageScaling()) document->updateLayoutIgnorePendingStylesheets(); - view->setScrollPosition(origin); + + if (!view->delegatesScrolling()) + view->setScrollPosition(origin); +#if USE(COORDINATED_GRAPHICS) + else + view->requestScrollPositionUpdate(origin); +#endif } +#if ENABLE(MEDIA_CONTROLS_SCRIPT) + if (inStableState) { + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->pageScaleFactorChangedAndStable(); + } + } +#endif return; } @@ -725,9 +861,7 @@ void Page::setPageScaleFactor(float scale, const IntPoint& origin) mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect())); } -#if USE(ACCELERATED_COMPOSITING) mainFrame().deviceOrPageScaleFactorChanged(); -#endif if (view && view->fixedElementsLayoutRelativeToFrame()) view->setViewportConstrainedObjectsNeedLayout(); @@ -735,29 +869,100 @@ void Page::setPageScaleFactor(float scale, const IntPoint& origin) if (view && view->scrollPosition() != origin) { if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout()) view->layout(); - view->setScrollPosition(origin); + + if (!view->delegatesScrolling()) + view->setScrollPosition(origin); +#if USE(COORDINATED_GRAPHICS) + else + view->requestScrollPositionUpdate(origin); +#endif + } + +#if ENABLE(MEDIA_CONTROLS_SCRIPT) + if (inStableState) { + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->pageScaleFactorChangedAndStable(); + } } +#else + UNUSED_PARAM(inStableState); +#endif } +void Page::setViewScaleFactor(float scale) +{ + if (m_viewScaleFactor == scale) + return; + + m_viewScaleFactor = scale; + PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this); +} void Page::setDeviceScaleFactor(float scaleFactor) { + ASSERT(scaleFactor > 0); + if (scaleFactor <= 0) + return; + if (m_deviceScaleFactor == scaleFactor) return; m_deviceScaleFactor = scaleFactor; setNeedsRecalcStyleInAllFrames(); -#if USE(ACCELERATED_COMPOSITING) mainFrame().deviceOrPageScaleFactorChanged(); - pageCache()->markPagesForDeviceScaleChanged(this); + PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this); + + GraphicsContext::updateDocumentMarkerResources(); + + mainFrame().pageOverlayController().didChangeDeviceScaleFactor(); +} + +void Page::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection) +{ + if (m_userInterfaceLayoutDirection == userInterfaceLayoutDirection) + return; + + m_userInterfaceLayoutDirection = userInterfaceLayoutDirection; +#if ENABLE(MEDIA_CONTROLS_SCRIPT) + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->userInterfaceLayoutDirectionChanged(); + } #endif +} - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) - frame->editor().deviceScaleFactorChanged(); +void Page::didStartProvisionalLoad() +{ + if (m_performanceMonitor) + m_performanceMonitor->didStartProvisionalLoad(); +} - pageCache()->markPagesForFullStyleRecalc(this); - GraphicsContext::updateDocumentMarkerResources(); +void Page::didFinishLoad() +{ + resetRelevantPaintedObjectCounter(); + + if (m_performanceMonitor) + m_performanceMonitor->didFinishLoad(); +} + +bool Page::isOnlyNonUtilityPage() const +{ + return !isUtilityPage() && nonUtilityPageCount == 1; +} + +void Page::setTopContentInset(float contentInset) +{ + if (m_topContentInset == contentInset) + return; + + m_topContentInset = contentInset; + + if (FrameView* view = mainFrame().view()) + view->topContentInsetDidChange(m_topContentInset); } void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations) @@ -786,12 +991,32 @@ void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars) if (!scrollableAreas) continue; - for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) { - ScrollableArea* scrollableArea = *it; + for (auto& scrollableArea : *scrollableAreas) scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars); - } } } + +void Page::setVerticalScrollElasticity(ScrollElasticity elasticity) +{ + if (m_verticalScrollElasticity == elasticity) + return; + + m_verticalScrollElasticity = elasticity; + + if (FrameView* view = mainFrame().view()) + view->setVerticalScrollElasticity(elasticity); +} + +void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity) +{ + if (m_horizontalScrollElasticity == elasticity) + return; + + m_horizontalScrollElasticity = elasticity; + + if (FrameView* view = mainFrame().view()) + view->setHorizontalScrollElasticity(elasticity); +} void Page::setPagination(const Pagination& pagination) { @@ -801,7 +1026,16 @@ void Page::setPagination(const Pagination& pagination) m_pagination = pagination; setNeedsRecalcStyleInAllFrames(); - pageCache()->markPagesForFullStyleRecalc(this); +} + +void Page::setPaginationLineGridEnabled(bool enabled) +{ + if (m_paginationLineGridEnabled == enabled) + return; + + m_paginationLineGridEnabled = enabled; + + setNeedsRecalcStyleInAllFrames(); } unsigned Page::pageCount() const @@ -813,16 +1047,16 @@ unsigned Page::pageCount() const document->updateLayoutIgnorePendingStylesheets(); RenderView* contentRenderer = mainFrame().contentRenderer(); - return contentRenderer ? contentRenderer->columnCount(contentRenderer->columnInfo()) : 0; + return contentRenderer ? contentRenderer->pageCount() : 0; } void Page::setIsInWindow(bool isInWindow) { - if (m_isInWindow == isInWindow) - return; - - m_isInWindow = isInWindow; + setActivityState(isInWindow ? m_activityState | ActivityState::IsInWindow : m_activityState & ~ActivityState::IsInWindow); +} +void Page::setIsInWindowInternal(bool isInWindow) +{ for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { if (FrameView* frameView = frame->view()) frameView->setIsInWindow(isInWindow); @@ -832,6 +1066,16 @@ void Page::setIsInWindow(bool isInWindow) resumeAnimatingImages(); } +void Page::addActivityStateChangeObserver(ActivityStateChangeObserver& observer) +{ + m_activityStateChangeObservers.add(&observer); +} + +void Page::removeActivityStateChangeObserver(ActivityStateChangeObserver& observer) +{ + m_activityStateChangeObservers.remove(&observer); +} + void Page::suspendScriptedAnimations() { m_scriptedAnimationsSuspended = true; @@ -850,9 +1094,12 @@ void Page::resumeScriptedAnimations() } } -void Page::setIsVisuallyIdle(bool isVisuallyIdle) +void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle) { - m_pageThrottler->setIsVisuallyIdle(isVisuallyIdle); + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (frame->document()) + frame->document()->scriptedAnimationControllerSetThrottled(isVisuallyIdle); + } } void Page::userStyleSheetLocationChanged() @@ -862,7 +1109,7 @@ void Page::userStyleSheetLocationChanged() URL url = m_settings->userStyleSheetLocation(); // Allow any local file URL scheme to be loaded. - if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol())) + if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol().toStringWithoutCopying())) m_userStyleSheetPath = url.fileSystemPath(); else m_userStyleSheetPath = String(); @@ -877,13 +1124,13 @@ void Page::userStyleSheetLocationChanged() m_didLoadUserStyleSheet = true; Vector<char> styleSheetAsUTF8; - if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace)) + if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreSpacesAndNewLines)) m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size()); } for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { if (frame->document()) - frame->document()->styleSheetCollection().updatePageUserSheet(); + frame->document()->extensionStyleSheets().updatePageUserSheet(); } } @@ -921,57 +1168,36 @@ const String& Page::userStyleSheet() const if (!data) return m_userStyleSheet; - RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css"); - m_userStyleSheet = decoder->decode(data->data(), data->size()); - m_userStyleSheet.append(decoder->flush()); + m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size()); return m_userStyleSheet; } -void Page::removeAllVisitedLinks() +void Page::invalidateStylesForAllLinks() { - if (!allPages) - return; - HashSet<PageGroup*> groups; - HashSet<Page*>::iterator pagesEnd = allPages->end(); - for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { - if (PageGroup* group = (*it)->groupPtr()) - groups.add(group); + for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->visitedLinkState().invalidateStyleForAllLinks(); } - HashSet<PageGroup*>::iterator groupsEnd = groups.end(); - for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it) - (*it)->removeVisitedLinks(); } -void Page::allVisitedStateChanged(PageGroup* group) +void Page::invalidateStylesForLink(LinkHash linkHash) { - ASSERT(group); - if (!allPages) - return; - - HashSet<Page*>::iterator pagesEnd = allPages->end(); - for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { - Page* page = *it; - if (page->m_group != group) + for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) continue; - for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) - frame->document()->visitedLinkState().invalidateStyleForAllLinks(); + frame->document()->visitedLinkState().invalidateStyleForLink(linkHash); } } -void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash) +void Page::invalidateInjectedStyleSheetCacheInAllFrames() { - ASSERT(group); - if (!allPages) - return; - - HashSet<Page*>::iterator pagesEnd = allPages->end(); - for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { - Page* page = *it; - if (page->m_group != group) + for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) { + Document* document = frame->document(); + if (!document) continue; - for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) - frame->document()->visitedLinkState().invalidateStyleForLink(linkHash); + document->extensionStyleSheets().invalidateInjectedStyleSheetCache(); } } @@ -982,39 +1208,45 @@ void Page::setDebugger(JSC::Debugger* debugger) m_debugger = debugger; - for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) + for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) frame->script().attachDebugger(m_debugger); } StorageNamespace* Page::sessionStorage(bool optionalCreate) { if (!m_sessionStorage && optionalCreate) - m_sessionStorage = StorageNamespace::sessionStorageNamespace(this); + m_sessionStorage = m_storageNamespaceProvider->createSessionStorageNamespace(*this, m_settings->sessionStorageQuota()); return m_sessionStorage.get(); } -void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage) +void Page::setSessionStorage(RefPtr<StorageNamespace>&& newStorage) { - m_sessionStorage = newStorage; + m_sessionStorage = WTFMove(newStorage); } -void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay) +StorageNamespace* Page::ephemeralLocalStorage(bool optionalCreate) { - if (customHTMLTokenizerTimeDelay < 0) { - m_customHTMLTokenizerTimeDelay = -1; - return; - } - m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay; + if (!m_ephemeralLocalStorage && optionalCreate) + m_ephemeralLocalStorage = m_storageNamespaceProvider->createEphemeralLocalStorageNamespace(*this, m_settings->sessionStorageQuota()); + + return m_ephemeralLocalStorage.get(); } -void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize) +void Page::setEphemeralLocalStorage(RefPtr<StorageNamespace>&& newStorage) { - if (customHTMLTokenizerChunkSize < 0) { - m_customHTMLTokenizerChunkSize = -1; - return; - } - m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize; + m_ephemeralLocalStorage = WTFMove(newStorage); +} + +bool Page::hasCustomHTMLTokenizerTimeDelay() const +{ + return m_settings->maxParseDuration() != -1; +} + +double Page::customHTMLTokenizerTimeDelay() const +{ + ASSERT(m_settings->maxParseDuration() != -1); + return m_settings->maxParseDuration(); } void Page::setMemoryCacheClientCallsEnabled(bool enabled) @@ -1030,91 +1262,211 @@ void Page::setMemoryCacheClientCallsEnabled(bool enabled) frame->loader().tellClientAboutPastMemoryCacheLoads(); } -void Page::setMinimumTimerInterval(double minimumTimerInterval) +void Page::hiddenPageDOMTimerThrottlingStateChanged() { - double oldTimerInterval = m_minimumTimerInterval; - m_minimumTimerInterval = minimumTimerInterval; - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) { - if (frame->document()) - frame->document()->adjustMinimumTimerInterval(oldTimerInterval); - } + // Disable & reengage to ensure state is updated. + setTimerThrottlingState(TimerThrottlingState::Disabled); + updateTimerThrottlingState(); } -double Page::minimumTimerInterval() const +void Page::updateTimerThrottlingState() { - return m_minimumTimerInterval; + // Timer throttling disabled if page is visually active, or disabled by setting. + if (!m_settings->hiddenPageDOMTimerThrottlingEnabled() || !(m_activityState & ActivityState::IsVisuallyIdle)) { + setTimerThrottlingState(TimerThrottlingState::Disabled); + return; + } + + // If the page is visible (but idle), there is any activity (loading, media playing, etc), or per setting, + // we allow timer throttling, but not increasing timer throttling. + if (!m_settings->hiddenPageDOMTimerThrottlingAutoIncreases() + || m_activityState & (ActivityState::IsVisible | ActivityState::IsAudible | ActivityState::IsLoading)) { + setTimerThrottlingState(TimerThrottlingState::Enabled); + return; + } + + // If we get here increasing timer throttling is enabled. + setTimerThrottlingState(TimerThrottlingState::EnabledIncreasing); } -void Page::setTimerAlignmentInterval(double interval) +void Page::setTimerThrottlingState(TimerThrottlingState state) { - if (interval == m_timerAlignmentInterval) + if (state == m_timerThrottlingState) return; - m_timerAlignmentInterval = interval; - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) { - if (frame->document()) - frame->document()->didChangeTimerAlignmentInterval(); + m_timerThrottlingState = state; + m_timerThrottlingStateLastChangedTime = std::chrono::steady_clock::now(); + + updateDOMTimerAlignmentInterval(); + + // When throttling is disabled, release all throttled timers. + if (state == TimerThrottlingState::Disabled) { + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (auto* document = frame->document()) + document->didChangeTimerAlignmentInterval(); + } } } -double Page::timerAlignmentInterval() const +void Page::setTimerAlignmentIntervalIncreaseLimit(std::chrono::milliseconds limit) { - return m_timerAlignmentInterval; + m_timerAlignmentIntervalIncreaseLimit = limit; + + // If (m_timerAlignmentIntervalIncreaseLimit < m_timerAlignmentInterval) then we need + // to update m_timerAlignmentInterval, if greater then need to restart the increase timer. + if (m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing) + updateDOMTimerAlignmentInterval(); +} + +void Page::updateDOMTimerAlignmentInterval() +{ + bool needsIncreaseTimer = false; + + switch (m_timerThrottlingState) { + case TimerThrottlingState::Disabled: + m_timerAlignmentInterval = DOMTimer::defaultAlignmentInterval(); + break; + + case TimerThrottlingState::Enabled: + m_timerAlignmentInterval = DOMTimer::hiddenPageAlignmentInterval(); + break; + + case TimerThrottlingState::EnabledIncreasing: + // For pages in prerender state maximum throttling kicks in immediately. + if (m_isPrerender) + m_timerAlignmentInterval = m_timerAlignmentIntervalIncreaseLimit; + else { + ASSERT(m_timerThrottlingStateLastChangedTime.time_since_epoch() != std::chrono::steady_clock::duration::zero()); + m_timerAlignmentInterval = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_timerThrottlingStateLastChangedTime); + // If we're below the limit, set the timer. If above, clamp to limit. + if (m_timerAlignmentInterval < m_timerAlignmentIntervalIncreaseLimit) + needsIncreaseTimer = true; + else + m_timerAlignmentInterval = m_timerAlignmentIntervalIncreaseLimit; + } + // Alignment interval should not be less than DOMTimer::hiddenPageAlignmentInterval(). + m_timerAlignmentInterval = std::max(m_timerAlignmentInterval, DOMTimer::hiddenPageAlignmentInterval()); + } + + // If throttling is enabled, auto-increasing of throttling is enabled, and the auto-increase + // limit has not yet been reached, and then arm the timer to consider an increase. Time to wait + // between increases is equal to the current throttle time. Since alinment interval increases + // exponentially, time between steps is exponential too. + if (!needsIncreaseTimer) + m_timerAlignmentIntervalIncreaseTimer.stop(); + else if (!m_timerAlignmentIntervalIncreaseTimer.isActive()) + m_timerAlignmentIntervalIncreaseTimer.startOneShot(m_timerAlignmentInterval); +} + +void Page::timerAlignmentIntervalIncreaseTimerFired() +{ + ASSERT(m_settings->hiddenPageDOMTimerThrottlingAutoIncreases()); + ASSERT(m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing); + ASSERT(m_timerAlignmentInterval < m_timerAlignmentIntervalIncreaseLimit); + + // Alignment interval is increased to equal the time the page has been throttled, to a limit. + updateDOMTimerAlignmentInterval(); } void Page::dnsPrefetchingStateChanged() { - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; frame->document()->initDNSPrefetch(); + } } Vector<Ref<PluginViewBase>> Page::pluginViews() { Vector<Ref<PluginViewBase>> views; - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { - FrameView* view = frame->view(); + auto* view = frame->view(); if (!view) break; - - for (auto it = view->children().begin(), end = view->children().end(); it != end; ++it) { - Widget* widget = (*it).get(); - if (widget->isPluginViewBase()) - views.append(*toPluginViewBase(widget)); + for (auto& widget : view->children()) { + if (is<PluginViewBase>(widget.get())) + views.append(downcast<PluginViewBase>(widget.get())); } } - return views; } void Page::storageBlockingStateChanged() { - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; frame->document()->storageBlockingStateDidChange(); + } // Collect the PluginViews in to a vector to ensure that action the plug-in takes // from below storageBlockingStateChanged does not affect their lifetime. - auto views = pluginViews(); + for (auto& view : pluginViews()) + view->storageBlockingStateChanged(); +} + +void Page::enableLegacyPrivateBrowsing(bool privateBrowsingEnabled) +{ + // Don't allow changing the legacy private browsing state if we have set a session ID. + ASSERT(m_sessionID == SessionID::defaultSessionID() || m_sessionID == SessionID::legacyPrivateSessionID()); - for (unsigned i = 0; i < views.size(); ++i) - views[i]->storageBlockingStateChanged(); + setSessionID(privateBrowsingEnabled ? SessionID::legacyPrivateSessionID() : SessionID::defaultSessionID()); } -void Page::privateBrowsingStateChanged() +void Page::updateIsPlayingMedia(uint64_t sourceElementID) { - bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled(); + MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying; + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (Document* document = frame->document()) + state |= document->mediaState(); + } - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) - frame->document()->privateBrowsingStateDidChange(); + if (state == m_mediaState) + return; - // Collect the PluginViews in to a vector to ensure that action the plug-in takes - // from below privateBrowsingStateChanged does not affect their lifetime. - auto views = pluginViews(); + m_mediaState = state; - for (unsigned i = 0; i < views.size(); ++i) - views[i]->privateBrowsingStateChanged(privateBrowsingEnabled); + chrome().client().isPlayingMediaDidChange(state, sourceElementID); } +void Page::setMuted(MediaProducer::MutedStateFlags muted) +{ + if (m_mutedState == muted) + return; + + m_mutedState = muted; + + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->pageMutedStateDidChange(); + } +} + +#if ENABLE(MEDIA_SESSION) +void Page::handleMediaEvent(MediaEventType eventType) +{ + switch (eventType) { + case MediaEventType::PlayPause: + MediaSessionManager::singleton().togglePlayback(); + break; + case MediaEventType::TrackNext: + MediaSessionManager::singleton().skipToNextTrack(); + break; + case MediaEventType::TrackPrevious: + MediaSessionManager::singleton().skipToPreviousTrack(); + break; + } +} + +void Page::setVolumeOfMediaElement(double volume, uint64_t elementID) +{ + if (HTMLMediaElement* element = HTMLMediaElement::elementWithID(elementID)) + element->setVolume(volume, ASSERT_NO_EXCEPTION); +} +#endif + #if !ASSERT_DISABLED void Page::checkSubframeCountConsistency() const { @@ -1128,86 +1480,127 @@ void Page::checkSubframeCountConsistency() const } #endif -void Page::throttleTimers() +void Page::resumeAnimatingImages() { -#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) - if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) - setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval()); -#endif + // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.) + // require that we repaint animated images to kickstart the animation loop. + if (FrameView* view = mainFrame().view()) + view->resumeVisibleImageAnimationsIncludingSubframes(); } -void Page::unthrottleTimers() +void Page::setActivityState(ActivityState::Flags activityState) { -#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) - if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) - setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()); -#endif + ActivityState::Flags changed = m_activityState ^ activityState; + if (!changed) + return; + + ActivityState::Flags oldActivityState = m_activityState; + + bool wasVisibleAndActive = isVisibleAndActive(); + m_activityState = activityState; + + m_focusController->setActivityState(activityState); + + if (changed & ActivityState::IsVisible) + setIsVisibleInternal(activityState & ActivityState::IsVisible); + if (changed & ActivityState::IsInWindow) + setIsInWindowInternal(activityState & ActivityState::IsInWindow); + if (changed & ActivityState::IsVisuallyIdle) + setIsVisuallyIdleInternal(activityState & ActivityState::IsVisuallyIdle); + if (changed & ActivityState::WindowIsActive) { + if (auto* view = m_mainFrame->view()) + view->updateTiledBackingAdaptiveSizing(); + } + + if (changed & (ActivityState::IsVisible | ActivityState::IsVisuallyIdle | ActivityState::IsAudible | ActivityState::IsLoading)) + updateTimerThrottlingState(); + + for (auto* observer : m_activityStateChangeObservers) + observer->activityStateDidChange(oldActivityState, m_activityState); + + if (wasVisibleAndActive != isVisibleAndActive()) + PlatformMediaSessionManager::updateNowPlayingInfoIfNecessary(); + + if (m_performanceMonitor) + m_performanceMonitor->activityStateChanged(oldActivityState, activityState); } -void Page::resumeAnimatingImages() +bool Page::isVisibleAndActive() const { - // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.) - // require that we repaint animated images to kickstart the animation loop. + return (m_activityState & ActivityState::IsVisible) && (m_activityState & ActivityState::WindowIsActive); +} + +bool Page::isWindowActive() const +{ + return m_activityState & ActivityState::WindowIsActive; +} + +void Page::setIsVisible(bool isVisible) +{ + if (isVisible) + setActivityState((m_activityState & ~ActivityState::IsVisuallyIdle) | ActivityState::IsVisible | ActivityState::IsVisibleOrOccluded); + else + setActivityState((m_activityState & ~(ActivityState::IsVisible | ActivityState::IsVisibleOrOccluded)) | ActivityState::IsVisuallyIdle); +} + +enum class SVGAnimationsState { Paused, Resumed }; +static inline void setSVGAnimationsState(Page& page, SVGAnimationsState state) +{ + for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) { + auto* document = frame->document(); + if (!document) + continue; + + if (!document->svgExtensions()) + continue; - for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) - CachedImage::resumeAnimatingImagesForLoader(frame->document()->cachedResourceLoader()); + if (state == SVGAnimationsState::Paused) + document->accessSVGExtensions().pauseAnimations(); + else + document->accessSVGExtensions().unpauseAnimations(); + } } -void Page::setIsVisible(bool isVisible, bool isInitialState) +void Page::setIsVisibleInternal(bool isVisible) { // FIXME: The visibility state should be stored on the top-level document. // https://bugs.webkit.org/show_bug.cgi?id=116769 - if (m_isVisible == isVisible) - return; - m_isVisible = isVisible; - if (isVisible) { m_isPrerender = false; - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { - if (FrameView* frameView = frame->view()) - frameView->didMoveOnscreen(); - } - resumeScriptedAnimations(); +#if PLATFORM(IOS) + resumeDeviceMotionAndOrientationUpdates(); +#endif if (FrameView* view = mainFrame().view()) view->show(); - unthrottleTimers(); - if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) mainFrame().animation().resumeAnimations(); + setSVGAnimationsState(*this, SVGAnimationsState::Resumed); + resumeAnimatingImages(); } -#if ENABLE(PAGE_VISIBILITY_API) - if (!isInitialState) { - Vector<Ref<Document>> documents; - for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) - documents.append(*frame->document()); + Vector<Ref<Document>> documents; + for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) + documents.append(*frame->document()); - for (size_t i = 0, size = documents.size(); i < size; ++i) - documents[i]->visibilityStateChanged(); - } -#else - UNUSED_PARAM(isInitialState); -#endif + for (auto& document : documents) + document->visibilityStateChanged(); if (!isVisible) { - if (m_pageThrottler->shouldThrottleTimers()) - throttleTimers(); - if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) mainFrame().animation().suspendAnimations(); - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { - if (FrameView* frameView = frame->view()) - frameView->willMoveOffscreen(); - } + setSVGAnimationsState(*this, SVGAnimationsState::Paused); +#if PLATFORM(IOS) + suspendDeviceMotionAndOrientationUpdates(); +#endif suspendScriptedAnimations(); if (FrameView* view = mainFrame().view()) @@ -1218,18 +1611,17 @@ void Page::setIsVisible(bool isVisible, bool isInitialState) void Page::setIsPrerender() { m_isPrerender = true; + updateDOMTimerAlignmentInterval(); } -#if ENABLE(PAGE_VISIBILITY_API) PageVisibilityState Page::visibilityState() const { - if (m_isVisible) - return PageVisibilityStateVisible; + if (isVisible()) + return PageVisibilityState::Visible; if (m_isPrerender) - return PageVisibilityStatePrerender; - return PageVisibilityStateHidden; + return PageVisibilityState::Prerender; + return PageVisibilityState::Hidden; } -#endif #if ENABLE(RUBBER_BANDING) void Page::addHeaderWithHeight(int headerHeight) @@ -1265,6 +1657,41 @@ void Page::addFooterWithHeight(int footerHeight) } #endif +void Page::incrementNestedRunLoopCount() +{ + m_nestedRunLoopCount++; +} + +void Page::decrementNestedRunLoopCount() +{ + ASSERT(m_nestedRunLoopCount); + if (m_nestedRunLoopCount <= 0) + return; + + m_nestedRunLoopCount--; + + if (!m_nestedRunLoopCount && m_unnestCallback) { + callOnMainThread([this] { + if (insideNestedRunLoop()) + return; + + // This callback may destruct the Page. + if (m_unnestCallback) { + auto callback = m_unnestCallback; + m_unnestCallback = nullptr; + callback(); + } + }); + } +} + +void Page::whenUnnested(std::function<void()> callback) +{ + ASSERT(!m_unnestCallback); + + m_unnestCallback = callback; +} + #if ENABLE(REMOTE_INSPECTOR) bool Page::remoteInspectionAllowed() const { @@ -1276,6 +1703,16 @@ void Page::setRemoteInspectionAllowed(bool allowed) m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed); } +String Page::remoteInspectionNameOverride() const +{ + return m_inspectorDebuggable->nameOverride(); +} + +void Page::setRemoteInspectionNameOverride(const String& name) +{ + m_inspectorDebuggable->setNameOverride(name); +} + void Page::remoteInspectorInformationDidChange() const { m_inspectorDebuggable->update(); @@ -1293,9 +1730,22 @@ void Page::removeLayoutMilestones(LayoutMilestones milestones) m_requestedLayoutMilestones &= ~milestones; } +Color Page::pageExtendedBackgroundColor() const +{ + FrameView* frameView = mainFrame().view(); + if (!frameView) + return Color(); + + RenderView* renderView = frameView->renderView(); + if (!renderView) + return Color(); + + return renderView->compositor().rootExtendedBackgroundColor(); +} + // These are magical constants that might be tweaked over time. -static double gMinimumPaintedAreaRatio = 0.1; -static double gMaximumUnpaintedAreaRatio = 0.04; +static const double gMinimumPaintedAreaRatio = 0.1; +static const double gMaximumUnpaintedAreaRatio = 0.04; bool Page::isCountingRelevantRepaintedObjects() const { @@ -1348,10 +1798,10 @@ void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& ob LayoutRect relevantRect = relevantViewRect(&object->view()); // The objects are only relevant if they are being painted within the viewRect(). - if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantRect))) + if (!objectPaintRect.intersects(snappedIntRect(relevantRect))) return; - IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect); + IntRect snappedPaintRect = snappedIntRect(objectPaintRect); // If this object was previously counted as an unpainted object, remove it from that HashSet // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap. @@ -1369,11 +1819,11 @@ void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& ob // If the rect straddles both Regions, split it appropriately. if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) { IntRect topIntersection = snappedPaintRect; - topIntersection.intersect(pixelSnappedIntRect(topRelevantRect)); + topIntersection.intersect(snappedIntRect(topRelevantRect)); m_topRelevantPaintedRegion.unite(topIntersection); IntRect bottomIntersection = snappedPaintRect; - bottomIntersection.intersect(pixelSnappedIntRect(bottomRelevantRect)); + bottomIntersection.intersect(snappedIntRect(bottomRelevantRect)); m_bottomRelevantPaintedRegion.unite(bottomIntersection); } else if (topRelevantRect.intersects(snappedPaintRect)) m_topRelevantPaintedRegion.unite(snappedPaintRect); @@ -1393,7 +1843,7 @@ void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& ob m_isCountingRelevantRepaintedObjects = false; resetRelevantPaintedObjectCounter(); if (Frame* frame = &mainFrame()) - frame->loader().didLayout(DidHitRelevantRepaintedObjectsAreaThreshold); + frame->loader().didReachLayoutMilestone(DidHitRelevantRepaintedObjectsAreaThreshold); } } @@ -1403,11 +1853,27 @@ void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& ob return; // The objects are only relevant if they are being painted within the relevantViewRect(). - if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantViewRect(&object->view())))) + if (!objectPaintRect.intersects(snappedIntRect(relevantViewRect(&object->view())))) return; m_relevantUnpaintedRenderObjects.add(object); - m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect)); + m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect)); +} + +void Page::suspendDeviceMotionAndOrientationUpdates() +{ + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (Document* document = frame->document()) + document->suspendDeviceMotionAndOrientationUpdates(); + } +} + +void Page::resumeDeviceMotionAndOrientationUpdates() +{ + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (Document* document = frame->document()) + document->resumeDeviceMotionAndOrientationUpdates(); + } } void Page::suspendActiveDOMObjectsAndAnimations() @@ -1464,89 +1930,298 @@ void Page::resetSeenMediaEngines() m_seenMediaEngines.clear(); } -std::unique_ptr<PageActivityAssertionToken> Page::createActivityToken() -{ - return m_pageThrottler->createActivityToken(); -} - -#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) -void Page::hiddenPageDOMTimerThrottlingStateChanged() -{ - if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) { -#if ENABLE(PAGE_VISIBILITY_API) - if (m_pageThrottler->shouldThrottleTimers()) - setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval()); -#endif - } else - setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval()); -} -#endif - -#if (ENABLE_PAGE_VISIBILITY_API) void Page::hiddenPageCSSAnimationSuspensionStateChanged() { - if (!m_isVisible) { + if (!isVisible()) { if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) mainFrame().animation().suspendAnimations(); else mainFrame().animation().resumeAnimations(); } } -#endif #if ENABLE(VIDEO_TRACK) void Page::captionPreferencesChanged() { - for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; frame->document()->captionPreferencesChanged(); + } } #endif -void Page::incrementFrameHandlingBeforeUnloadEventCount() +void Page::forbidPrompts() { - ++m_framesHandlingBeforeUnloadEvent; + ++m_forbidPromptsDepth; } -void Page::decrementFrameHandlingBeforeUnloadEventCount() +void Page::allowPrompts() { - ASSERT(m_framesHandlingBeforeUnloadEvent); - --m_framesHandlingBeforeUnloadEvent; + ASSERT(m_forbidPromptsDepth); + --m_forbidPromptsDepth; } -bool Page::isAnyFrameHandlingBeforeUnloadEvent() +bool Page::arePromptsAllowed() { - return m_framesHandlingBeforeUnloadEvent; + return !m_forbidPromptsDepth; } -void Page::setUserContentController(UserContentController* userContentController) +PluginInfoProvider& Page::pluginInfoProvider() { - if (m_userContentController) - m_userContentController->removePage(*this); + return m_pluginInfoProvider; +} - m_userContentController = userContentController; +UserContentProvider& Page::userContentProvider() +{ + return m_userContentProvider; +} - if (m_userContentController) - m_userContentController->addPage(*this); +void Page::setUserContentProvider(Ref<UserContentProvider>&& userContentProvider) +{ + m_userContentProvider->removePage(*this); + m_userContentProvider = WTFMove(userContentProvider); + m_userContentProvider->addPage(*this); + + invalidateInjectedStyleSheetCacheInAllFrames(); } -Page::PageClients::PageClients() - : alternativeTextClient(nullptr) - , chromeClient(nullptr) -#if ENABLE(CONTEXT_MENUS) - , contextMenuClient(nullptr) +void Page::setStorageNamespaceProvider(Ref<StorageNamespaceProvider>&& storageNamespaceProvider) +{ + m_storageNamespaceProvider->removePage(*this); + m_storageNamespaceProvider = WTFMove(storageNamespaceProvider); + m_storageNamespaceProvider->addPage(*this); + + // This needs to reset all the local storage namespaces of all the pages. +} + +VisitedLinkStore& Page::visitedLinkStore() +{ + return m_visitedLinkStore; +} + +void Page::setVisitedLinkStore(Ref<VisitedLinkStore>&& visitedLinkStore) +{ + m_visitedLinkStore->removePage(*this); + m_visitedLinkStore = WTFMove(visitedLinkStore); + m_visitedLinkStore->addPage(*this); + + invalidateStylesForAllLinks(); +} + +SessionID Page::sessionID() const +{ + return m_sessionID; +} + +void Page::setSessionID(SessionID sessionID) +{ + ASSERT(sessionID.isValid()); + +#if ENABLE(INDEXED_DATABASE) + if (sessionID != m_sessionID) + m_idbIDBConnectionToServer = nullptr; +#endif + + bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral()); + + m_sessionID = sessionID; + + if (!privateBrowsingStateChanged) + return; + + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->privateBrowsingStateDidChange(); + } + + // Collect the PluginViews in to a vector to ensure that action the plug-in takes + // from below privateBrowsingStateChanged does not affect their lifetime. + + for (auto& view : pluginViews()) + view->privateBrowsingStateChanged(sessionID.isEphemeral()); +} + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) +void Page::addPlaybackTargetPickerClient(uint64_t contextId) +{ + chrome().client().addPlaybackTargetPickerClient(contextId); +} + +void Page::removePlaybackTargetPickerClient(uint64_t contextId) +{ + chrome().client().removePlaybackTargetPickerClient(contextId); +} + +void Page::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool isVideo) +{ +#if PLATFORM(IOS) + // FIXME: refactor iOS implementation. + UNUSED_PARAM(contextId); + UNUSED_PARAM(location); + chrome().client().showPlaybackTargetPicker(isVideo); +#else + chrome().client().showPlaybackTargetPicker(contextId, location, isVideo); +#endif +} + +void Page::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state) +{ + chrome().client().playbackTargetPickerClientStateDidChange(contextId, state); +} + +void Page::setMockMediaPlaybackTargetPickerEnabled(bool enabled) +{ + chrome().client().setMockMediaPlaybackTargetPickerEnabled(enabled); +} + +void Page::setMockMediaPlaybackTargetPickerState(const String& name, MediaPlaybackTargetContext::State state) +{ + chrome().client().setMockMediaPlaybackTargetPickerState(name, state); +} + +void Page::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target) +{ + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->setPlaybackTarget(contextId, target.copyRef()); + } +} + +void Page::playbackTargetAvailabilityDidChange(uint64_t contextId, bool available) +{ + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->playbackTargetAvailabilityDidChange(contextId, available); + } +} + +void Page::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay) +{ + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (!frame->document()) + continue; + frame->document()->setShouldPlayToPlaybackTarget(clientId, shouldPlay); + } +} #endif - , editorClient(nullptr) - , dragClient(nullptr) - , inspectorClient(nullptr) - , plugInClient(nullptr) - , progressTrackerClient(nullptr) - , validationMessageClient(nullptr) - , loaderClientForMainFrame(nullptr) + +WheelEventTestTrigger& Page::ensureTestTrigger() { + if (!m_testTrigger) { + m_testTrigger = adoptRef(new WheelEventTestTrigger()); + // We need to update the scrolling coordinator so that the mainframe scrolling node can expect wheel event test triggers. + if (auto* frameView = mainFrame().view()) { + if (m_scrollingCoordinator) + m_scrollingCoordinator->updateExpectsWheelEventTestTriggerWithFrameView(*frameView); + } + } + + return *m_testTrigger; } -Page::PageClients::~PageClients() +#if ENABLE(VIDEO) +void Page::setAllowsMediaDocumentInlinePlayback(bool flag) +{ + if (m_allowsMediaDocumentInlinePlayback == flag) + return; + m_allowsMediaDocumentInlinePlayback = flag; + + Vector<Ref<Document>> documents; + for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) + documents.append(*frame->document()); + + for (auto& document : documents) + document->allowsMediaDocumentInlinePlaybackChanged(); +} +#endif + +#if ENABLE(INDEXED_DATABASE) +IDBClient::IDBConnectionToServer& Page::idbConnection() +{ + if (!m_idbIDBConnectionToServer) + m_idbIDBConnectionToServer = &databaseProvider().idbConnectionToServerForSession(m_sessionID); + + return *m_idbIDBConnectionToServer; +} +#endif + +#if ENABLE(RESOURCE_USAGE) +void Page::setResourceUsageOverlayVisible(bool visible) +{ + if (!visible) { + m_resourceUsageOverlay = nullptr; + return; + } + + if (!m_resourceUsageOverlay && m_settings->acceleratedCompositingEnabled()) + m_resourceUsageOverlay = std::make_unique<ResourceUsageOverlay>(*this); +} +#endif + +bool Page::isAlwaysOnLoggingAllowed() const { + return m_sessionID.isAlwaysOnLoggingAllowed(); } +String Page::captionUserPreferencesStyleSheet() +{ + return m_captionUserPreferencesStyleSheet; +} + +void Page::setCaptionUserPreferencesStyleSheet(const String& styleSheet) +{ + if (m_captionUserPreferencesStyleSheet == styleSheet) + return; + + m_captionUserPreferencesStyleSheet = styleSheet; + + invalidateInjectedStyleSheetCacheInAllFrames(); +} + +void Page::accessibilitySettingsDidChange() +{ + bool neededRecalc = false; + + for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (Document* document = frame->document()) { + auto* styleResolver = document->styleScope().resolverIfExists(); + if (styleResolver && styleResolver->hasMediaQueriesAffectedByAccessibilitySettingsChange()) { + document->styleScope().didChangeStyleSheetEnvironment(); + neededRecalc = true; + // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds. + InspectorInstrumentation::mediaQueryResultChanged(*document); + } + } + } + + if (neededRecalc) + LOG(Layout, "hasMediaQueriesAffectedByAccessibilitySettingsChange, enqueueing style recalc"); +} + +#if ENABLE(DATA_INTERACTION) + +bool Page::hasDataInteractionAtPosition(const FloatPoint& position) const +{ + auto currentSelection = m_mainFrame->selection().selection(); + if (!currentSelection.isRange()) + return false; + + if (auto selectedRange = currentSelection.toNormalizedRange()) { + Vector<SelectionRect> selectionRects; + selectedRange->collectSelectionRects(selectionRects); + for (auto selectionRect : selectionRects) { + if (FloatRect(selectionRect.rect()).contains(position)) + return true; + } + } + + return false; +} + +#endif + } // namespace WebCore |