2 * Copyright (C) 2006-2015 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 #include "ActivityStateChangeObserver.h"
24 #include "AlternativeTextClient.h"
25 #include "AnimationController.h"
26 #include "ApplicationCacheStorage.h"
27 #include "BackForwardClient.h"
28 #include "BackForwardController.h"
30 #include "ChromeClient.h"
31 #include "ClientRectList.h"
32 #include "ContextMenuClient.h"
33 #include "ContextMenuController.h"
34 #include "DatabaseProvider.h"
35 #include "DiagnosticLoggingClient.h"
36 #include "DocumentLoader.h"
37 #include "DocumentMarkerController.h"
38 #include "DragController.h"
40 #include "EditorClient.h"
41 #include "EmptyClients.h"
43 #include "EventNames.h"
44 #include "ExceptionCode.h"
45 #include "ExceptionCodePlaceholder.h"
46 #include "ExtensionStyleSheets.h"
47 #include "FileSystem.h"
48 #include "FocusController.h"
49 #include "FrameLoader.h"
50 #include "FrameLoaderClient.h"
51 #include "FrameSelection.h"
52 #include "FrameTree.h"
53 #include "FrameView.h"
54 #include "HTMLElement.h"
55 #include "HistoryController.h"
56 #include "HistoryItem.h"
57 #include "InspectorController.h"
58 #include "InspectorInstrumentation.h"
60 #include "MainFrame.h"
61 #include "MediaCanStartListener.h"
62 #include "Navigator.h"
63 #include "NetworkStateNotifier.h"
64 #include "PageCache.h"
65 #include "PageConfiguration.h"
66 #include "PageConsoleClient.h"
67 #include "PageDebuggable.h"
68 #include "PageGroup.h"
69 #include "PageOverlayController.h"
70 #include "PlatformMediaSessionManager.h"
71 #include "PlugInClient.h"
72 #include "PluginData.h"
73 #include "PluginInfoProvider.h"
74 #include "PluginViewBase.h"
75 #include "PointerLockController.h"
76 #include "ProgressTracker.h"
77 #include "RenderLayerCompositor.h"
78 #include "RenderTheme.h"
79 #include "RenderView.h"
80 #include "RenderWidget.h"
81 #include "ResourceUsageOverlay.h"
82 #include "RuntimeEnabledFeatures.h"
83 #include "SchemeRegistry.h"
84 #include "ScriptController.h"
85 #include "ScrollingCoordinator.h"
87 #include "SharedBuffer.h"
88 #include "StorageArea.h"
89 #include "StorageNamespace.h"
90 #include "StorageNamespaceProvider.h"
91 #include "StyleResolver.h"
92 #include "StyleScope.h"
93 #include "SubframeLoader.h"
94 #include "TextResourceDecoder.h"
95 #include "UserContentProvider.h"
96 #include "UserInputBridge.h"
97 #include "ValidationMessageClient.h"
98 #include "VisitedLinkState.h"
99 #include "VisitedLinkStore.h"
100 #include "VoidCallback.h"
102 #include <wtf/RefCountedLeakCounter.h>
103 #include <wtf/StdLibExtras.h>
104 #include <wtf/text/Base64.h>
105 #include <wtf/text/StringHash.h>
107 #if ENABLE(WEB_REPLAY)
108 #include "ReplayController.h"
109 #include <replay/InputCursor.h>
112 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
113 #include "HTMLVideoElement.h"
114 #include "MediaPlaybackTarget.h"
117 #if ENABLE(MEDIA_SESSION)
118 #include "MediaSessionManager.h"
121 #if ENABLE(INDEXED_DATABASE)
122 #include "IDBConnectionToServer.h"
123 #include "InProcessIDBServer.h"
128 static HashSet<Page*>* allPages;
130 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
132 void Page::forEachPage(std::function<void(Page&)> function)
136 for (Page* page : *allPages)
140 static void networkStateChanged(bool isOnLine)
142 Vector<Ref<Frame>> frames;
144 // Get all the frames of all the pages in all the page groups
145 for (auto& page : *allPages) {
146 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
147 frames.append(*frame);
148 InspectorInstrumentation::networkStateChanged(*page);
151 AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent;
152 for (auto& frame : frames) {
153 if (!frame->document())
155 frame->document()->dispatchWindowEvent(Event::create(eventName, false, false));
159 static const ActivityState::Flags PageInitialActivityState = ActivityState::IsVisible | ActivityState::IsInWindow;
161 Page::Page(PageConfiguration&& pageConfiguration)
162 : m_chrome(std::make_unique<Chrome>(*this, *pageConfiguration.chromeClient))
163 , m_dragCaretController(std::make_unique<DragCaretController>())
164 #if ENABLE(DRAG_SUPPORT)
165 , m_dragController(std::make_unique<DragController>(*this, *pageConfiguration.dragClient))
167 , m_focusController(std::make_unique<FocusController>(*this, PageInitialActivityState))
168 #if ENABLE(CONTEXT_MENUS)
169 , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageConfiguration.contextMenuClient))
171 , m_userInputBridge(std::make_unique<UserInputBridge>(*this))
172 #if ENABLE(WEB_REPLAY)
173 , m_replayController(std::make_unique<ReplayController>(*this))
175 , m_inspectorController(std::make_unique<InspectorController>(*this, pageConfiguration.inspectorClient))
176 #if ENABLE(POINTER_LOCK)
177 , m_pointerLockController(std::make_unique<PointerLockController>(*this))
179 , m_settings(Settings::create(this))
180 , m_progress(std::make_unique<ProgressTracker>(*pageConfiguration.progressTrackerClient))
181 , m_backForwardController(std::make_unique<BackForwardController>(*this, *WTFMove(pageConfiguration.backForwardClient)))
182 , m_mainFrame(MainFrame::create(*this, pageConfiguration))
183 , m_theme(RenderTheme::themeForPage(this))
184 , m_editorClient(WTFMove(pageConfiguration.editorClient))
185 , m_plugInClient(pageConfiguration.plugInClient)
186 , m_validationMessageClient(WTFMove(pageConfiguration.validationMessageClient))
187 , m_diagnosticLoggingClient(WTFMove(pageConfiguration.diagnosticLoggingClient))
189 , m_openedByDOM(false)
190 , m_tabKeyCyclesThroughElements(true)
191 , m_defersLoading(false)
192 , m_defersLoadingCallCount(0)
193 , m_inLowQualityInterpolationMode(false)
194 , m_areMemoryCacheClientCallsEnabled(true)
196 , m_pageScaleFactor(1)
197 , m_zoomedOutPageScaleFactor(0)
198 , m_topContentInset(0)
199 #if ENABLE(TEXT_AUTOSIZING)
200 , m_textAutosizingWidth(0)
202 , m_suppressScrollbarAnimations(false)
203 , m_verticalScrollElasticity(ScrollElasticityAllowed)
204 , m_horizontalScrollElasticity(ScrollElasticityAllowed)
205 , m_didLoadUserStyleSheet(false)
206 , m_userStyleSheetModificationTime(0)
208 , m_debugger(nullptr)
209 , m_canStartMedia(true)
210 #if ENABLE(VIEW_MODE_CSS_MEDIA)
211 , m_viewMode(ViewModeWindowed)
212 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
213 , m_timerAlignmentInterval(DOMTimer::defaultAlignmentInterval())
214 , m_timerAlignmentIntervalIncreaseTimer(*this, &Page::timerAlignmentIntervalIncreaseTimerFired)
215 , m_isEditable(false)
216 , m_isPrerender(false)
217 , m_activityState(PageInitialActivityState)
218 , m_requestedLayoutMilestones(0)
221 , m_isCountingRelevantRepaintedObjects(false)
223 , m_isPainting(false)
225 , m_alternativeTextClient(pageConfiguration.alternativeTextClient)
226 , m_scriptedAnimationsSuspended(false)
227 , m_consoleClient(std::make_unique<PageConsoleClient>(*this))
228 #if ENABLE(REMOTE_INSPECTOR)
229 , m_inspectorDebuggable(std::make_unique<PageDebuggable>(*this))
231 , m_lastSpatialNavigationCandidatesCount(0) // NOTE: Only called from Internals for Spatial Navigation testing.
232 , m_forbidPromptsDepth(0)
233 , m_socketProvider(WTFMove(pageConfiguration.socketProvider))
234 , m_applicationCacheStorage(*WTFMove(pageConfiguration.applicationCacheStorage))
235 , m_databaseProvider(*WTFMove(pageConfiguration.databaseProvider))
236 , m_pluginInfoProvider(*WTFMove(pageConfiguration.pluginInfoProvider))
237 , m_storageNamespaceProvider(*WTFMove(pageConfiguration.storageNamespaceProvider))
238 , m_userContentProvider(*WTFMove(pageConfiguration.userContentProvider))
239 , m_visitedLinkStore(*WTFMove(pageConfiguration.visitedLinkStore))
240 , m_sessionID(SessionID::defaultSessionID())
243 updateTimerThrottlingState();
245 m_pluginInfoProvider->addPage(*this);
246 m_storageNamespaceProvider->addPage(*this);
247 m_userContentProvider->addPage(*this);
248 m_visitedLinkStore->addPage(*this);
251 allPages = new HashSet<Page*>;
253 networkStateNotifier().addNetworkStateChangeListener(networkStateChanged);
256 ASSERT(!allPages->contains(this));
260 pageCounter.increment();
263 #if ENABLE(REMOTE_INSPECTOR)
264 m_inspectorDebuggable->init();
268 platformInitialize();
274 m_validationMessageClient = nullptr;
275 m_diagnosticLoggingClient = nullptr;
276 m_mainFrame->setView(nullptr);
277 setGroupName(String());
278 allPages->remove(this);
280 m_settings->pageDestroyed();
282 m_inspectorController->inspectedPageDestroyed();
284 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
285 frame->willDetachPage();
286 frame->detachFromPage();
290 m_plugInClient->pageDestroyed();
291 if (m_alternativeTextClient)
292 m_alternativeTextClient->pageDestroyed();
294 if (m_scrollingCoordinator)
295 m_scrollingCoordinator->pageDestroyed();
297 backForward().close();
300 pageCounter.decrement();
303 m_pluginInfoProvider->removePage(*this);
304 m_storageNamespaceProvider->removePage(*this);
305 m_userContentProvider->removePage(*this);
306 m_visitedLinkStore->removePage(*this);
309 void Page::clearPreviousItemFromAllPages(HistoryItem* item)
314 for (auto& page : *allPages) {
315 HistoryController& controller = page->mainFrame().loader().history();
316 if (item == controller.previousItem()) {
317 controller.clearPreviousItem();
323 uint64_t Page::renderTreeSize() const
326 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
327 if (!frame->document() || !frame->document()->renderView())
329 total += frame->document()->renderView()->rendererCount();
334 ViewportArguments Page::viewportArguments() const
336 return mainFrame().document() ? mainFrame().document()->viewportArguments() : ViewportArguments();
339 ScrollingCoordinator* Page::scrollingCoordinator()
341 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) {
342 m_scrollingCoordinator = chrome().client().createScrollingCoordinator(this);
343 if (!m_scrollingCoordinator)
344 m_scrollingCoordinator = ScrollingCoordinator::create(this);
347 return m_scrollingCoordinator.get();
350 String Page::scrollingStateTreeAsText()
352 if (Document* document = m_mainFrame->document())
353 document->updateLayout();
355 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
356 return scrollingCoordinator->scrollingStateTreeAsText();
361 String Page::synchronousScrollingReasonsAsText()
363 if (Document* document = m_mainFrame->document())
364 document->updateLayout();
366 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
367 return scrollingCoordinator->synchronousScrollingReasonsAsText();
372 Ref<ClientRectList> Page::nonFastScrollableRects()
374 if (Document* document = m_mainFrame->document())
375 document->updateLayout();
377 Vector<IntRect> rects;
378 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
379 const EventTrackingRegions& eventTrackingRegions = scrollingCoordinator->absoluteEventTrackingRegions();
380 for (const auto& synchronousEventRegion : eventTrackingRegions.eventSpecificSynchronousDispatchRegions)
381 rects.appendVector(synchronousEventRegion.value.rects());
384 Vector<FloatQuad> quads(rects.size());
385 for (size_t i = 0; i < rects.size(); ++i)
386 quads[i] = FloatRect(rects[i]);
388 return ClientRectList::create(quads);
391 #if ENABLE(VIEW_MODE_CSS_MEDIA)
392 struct ViewModeInfo {
396 static const int viewModeMapSize = 5;
397 static const ViewModeInfo viewModeMap[viewModeMapSize] = {
398 {"windowed", Page::ViewModeWindowed},
399 {"floating", Page::ViewModeFloating},
400 {"fullscreen", Page::ViewModeFullscreen},
401 {"maximized", Page::ViewModeMaximized},
402 {"minimized", Page::ViewModeMinimized}
405 Page::ViewMode Page::stringToViewMode(const String& text)
407 for (auto& mode : viewModeMap) {
408 if (text == mode.name)
411 return Page::ViewModeInvalid;
414 void Page::setViewMode(ViewMode viewMode)
416 if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
419 m_viewMode = viewMode;
422 if (m_mainFrame->view())
423 m_mainFrame->view()->forceLayout();
425 if (m_mainFrame->document())
426 m_mainFrame->document()->styleScope().didChangeStyleSheetEnvironment();
428 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
430 bool Page::openedByDOM() const
432 return m_openedByDOM;
435 void Page::setOpenedByDOM()
437 m_openedByDOM = true;
440 void Page::goToItem(HistoryItem& item, FrameLoadType type)
442 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
443 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
444 Ref<HistoryItem> protector(item);
446 if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item))
447 m_mainFrame->loader().stopAllLoaders();
449 m_mainFrame->loader().history().goToItem(item, type);
452 void Page::setGroupName(const String& name)
454 if (m_group && !m_group->name().isEmpty()) {
455 ASSERT(m_group != m_singlePageGroup.get());
456 ASSERT(!m_singlePageGroup);
457 m_group->removePage(*this);
461 m_group = m_singlePageGroup.get();
463 m_singlePageGroup = nullptr;
464 m_group = PageGroup::pageGroup(name);
465 m_group->addPage(*this);
469 const String& Page::groupName() const
471 return m_group ? m_group->name() : nullAtom.string();
474 void Page::initGroup()
476 ASSERT(!m_singlePageGroup);
478 m_singlePageGroup = std::make_unique<PageGroup>(*this);
479 m_group = m_singlePageGroup.get();
482 void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment()
486 for (auto& page : *allPages) {
487 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
488 // If a change in the global environment has occurred, we need to
489 // make sure all the properties a recomputed, therefore we invalidate
490 // the properties cache.
491 if (!frame->document())
493 if (StyleResolver* styleResolver = frame->document()->styleScope().resolverIfExists())
494 styleResolver->invalidateMatchedPropertiesCache();
495 frame->document()->scheduleForcedStyleRecalc();
500 void Page::setNeedsRecalcStyleInAllFrames()
502 // FIXME: Figure out what this function is actually trying to add in different call sites.
503 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
504 if (Document* document = frame->document())
505 document->styleScope().didChangeStyleSheetEnvironment();
509 void Page::refreshPlugins(bool reload)
514 HashSet<PluginInfoProvider*> pluginInfoProviders;
516 Vector<Ref<Frame>> framesNeedingReload;
518 for (auto& page : *allPages) {
519 pluginInfoProviders.add(&page->pluginInfoProvider());
520 page->m_pluginData = nullptr;
525 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
526 if (frame->loader().subframeLoader().containsPlugins())
527 framesNeedingReload.append(*frame);
531 for (auto& pluginInfoProvider : pluginInfoProviders)
532 pluginInfoProvider->refreshPlugins();
534 for (auto& frame : framesNeedingReload)
535 frame->loader().reload();
538 PluginData& Page::pluginData()
541 m_pluginData = PluginData::create(*this);
542 return *m_pluginData;
545 bool Page::showAllPlugins() const
547 if (m_showAllPlugins)
550 if (Document* document = mainFrame().document()) {
551 if (SecurityOrigin* securityOrigin = document->securityOrigin())
552 return securityOrigin->isLocal();
558 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
560 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
561 if (!frame->document())
563 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
569 void Page::setCanStartMedia(bool canStartMedia)
571 if (m_canStartMedia == canStartMedia)
574 m_canStartMedia = canStartMedia;
576 while (m_canStartMedia) {
577 MediaCanStartListener* listener = takeAnyMediaCanStartListener();
580 listener->mediaCanStart();
584 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
587 ? curr->tree().traverseNextWithWrap(wrapFlag)
588 : curr->tree().traversePreviousWithWrap(wrapFlag);
591 bool Page::findString(const String& target, FindOptions options)
593 if (target.isEmpty())
596 bool shouldWrap = options & WrapAround;
597 Frame* frame = &focusController().focusedOrMainFrame();
598 Frame* startFrame = frame;
600 if (frame->editor().findString(target, (options & ~WrapAround) | StartInSelection)) {
601 if (frame != startFrame)
602 startFrame->selection().clear();
603 focusController().setFocusedFrame(frame);
606 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
607 } while (frame && frame != startFrame);
609 // Search contents of startFrame, on the other side of the selection that we did earlier.
610 // We cheat a bit and just research with wrap on
611 if (shouldWrap && !startFrame->selection().isNone()) {
612 bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection);
613 focusController().setFocusedFrame(frame);
620 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>& matchRanges, int& indexForSelection)
622 indexForSelection = 0;
624 Frame* frame = &mainFrame();
625 Frame* frameWithSelection = nullptr;
627 frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges.size()) : 0, true, &matchRanges);
628 if (frame->selection().isRange())
629 frameWithSelection = frame;
630 frame = incrementFrame(frame, true, false);
633 if (matchRanges.isEmpty())
636 if (frameWithSelection) {
637 indexForSelection = NoMatchAfterUserSelection;
638 RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange();
639 if (options & Backwards) {
640 for (size_t i = matchRanges.size(); i > 0; --i) {
641 auto result = selectedRange->compareBoundaryPoints(Range::END_TO_START, *matchRanges[i - 1]);
642 if (!result.hasException() && result.releaseReturnValue() > 0) {
643 indexForSelection = i - 1;
648 for (size_t i = 0, size = matchRanges.size(); i < size; ++i) {
649 auto result = selectedRange->compareBoundaryPoints(Range::START_TO_END, *matchRanges[i]);
650 if (!result.hasException() && result.releaseReturnValue() < 0) {
651 indexForSelection = i;
657 if (options & Backwards)
658 indexForSelection = matchRanges.size() - 1;
660 indexForSelection = 0;
664 RefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
666 if (target.isEmpty())
669 if (referenceRange && referenceRange->ownerDocument().page() != this)
672 bool shouldWrap = options & WrapAround;
673 Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame();
674 Frame* startFrame = frame;
676 if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
679 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
680 } while (frame && frame != startFrame);
682 // Search contents of startFrame, on the other side of the reference range that we did earlier.
683 // We cheat a bit and just search again with wrap on.
684 if (shouldWrap && referenceRange) {
685 if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
692 unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches)
694 if (target.isEmpty())
697 unsigned matchCount = 0;
699 Frame* frame = &mainFrame();
701 if (shouldMarkMatches == MarkMatches)
702 frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches);
703 matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0);
704 frame = incrementFrame(frame, true, false);
710 unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount)
712 return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches);
715 unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount)
717 return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches);
720 void Page::unmarkAllTextMatches()
722 Frame* frame = &mainFrame();
724 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
725 frame = incrementFrame(frame, true, false);
729 const VisibleSelection& Page::selection() const
731 return focusController().focusedOrMainFrame().selection().selection();
734 void Page::setDefersLoading(bool defers)
736 if (!m_settings->loadDeferringEnabled())
739 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
740 ASSERT(defers || m_defersLoadingCallCount);
741 if (defers && ++m_defersLoadingCallCount > 1)
743 if (!defers && --m_defersLoadingCallCount)
746 ASSERT(!m_defersLoadingCallCount);
747 if (defers == m_defersLoading)
751 m_defersLoading = defers;
752 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
753 frame->loader().setDefersLoading(defers);
756 void Page::clearUndoRedoOperations()
758 m_editorClient->clearUndoRedoOperations();
761 bool Page::inLowQualityImageInterpolationMode() const
763 return m_inLowQualityInterpolationMode;
766 void Page::setInLowQualityImageInterpolationMode(bool mode)
768 m_inLowQualityInterpolationMode = mode;
771 DiagnosticLoggingClient& Page::diagnosticLoggingClient() const
773 static NeverDestroyed<EmptyDiagnosticLoggingClient> dummyClient;
774 if (!settings().diagnosticLoggingEnabled() || !m_diagnosticLoggingClient)
777 return *m_diagnosticLoggingClient;
780 void Page::setMediaVolume(float volume)
782 if (volume < 0 || volume > 1)
785 if (m_mediaVolume == volume)
788 m_mediaVolume = volume;
789 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
790 if (!frame->document())
792 frame->document()->mediaVolumeDidChange();
796 void Page::setZoomedOutPageScaleFactor(float scale)
798 if (m_zoomedOutPageScaleFactor == scale)
800 m_zoomedOutPageScaleFactor = scale;
802 mainFrame().deviceOrPageScaleFactorChanged();
805 void Page::setPageScaleFactor(float scale, const IntPoint& origin, bool inStableState)
807 Document* document = mainFrame().document();
808 FrameView* view = document->view();
810 if (scale == m_pageScaleFactor) {
811 if (view && view->scrollPosition() != origin) {
812 if (!m_settings->delegatesPageScaling())
813 document->updateLayoutIgnorePendingStylesheets();
815 if (!view->delegatesScrolling())
816 view->setScrollPosition(origin);
817 #if USE(COORDINATED_GRAPHICS)
819 view->requestScrollPositionUpdate(origin);
822 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
824 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
825 if (!frame->document())
827 frame->document()->pageScaleFactorChangedAndStable();
834 m_pageScaleFactor = scale;
836 if (!m_settings->delegatesPageScaling()) {
837 if (document->renderView())
838 document->renderView()->setNeedsLayout();
840 document->recalcStyle(Style::Force);
842 // Transform change on RenderView doesn't trigger repaint on non-composited contents.
843 mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
846 mainFrame().deviceOrPageScaleFactorChanged();
848 if (view && view->fixedElementsLayoutRelativeToFrame())
849 view->setViewportConstrainedObjectsNeedLayout();
851 if (view && view->scrollPosition() != origin) {
852 if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout())
855 if (!view->delegatesScrolling())
856 view->setScrollPosition(origin);
857 #if USE(COORDINATED_GRAPHICS)
859 view->requestScrollPositionUpdate(origin);
863 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
865 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
866 if (!frame->document())
868 frame->document()->pageScaleFactorChangedAndStable();
872 UNUSED_PARAM(inStableState);
876 void Page::setViewScaleFactor(float scale)
878 if (m_viewScaleFactor == scale)
881 m_viewScaleFactor = scale;
882 PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
885 void Page::setDeviceScaleFactor(float scaleFactor)
887 ASSERT(scaleFactor > 0);
888 if (scaleFactor <= 0)
891 if (m_deviceScaleFactor == scaleFactor)
894 m_deviceScaleFactor = scaleFactor;
895 setNeedsRecalcStyleInAllFrames();
897 mainFrame().deviceOrPageScaleFactorChanged();
898 PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
900 GraphicsContext::updateDocumentMarkerResources();
902 mainFrame().pageOverlayController().didChangeDeviceScaleFactor();
905 void Page::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
907 if (m_userInterfaceLayoutDirection == userInterfaceLayoutDirection)
910 m_userInterfaceLayoutDirection = userInterfaceLayoutDirection;
911 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
912 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
913 if (!frame->document())
915 frame->document()->userInterfaceLayoutDirectionChanged();
920 void Page::setTopContentInset(float contentInset)
922 if (m_topContentInset == contentInset)
925 m_topContentInset = contentInset;
927 if (FrameView* view = mainFrame().view())
928 view->topContentInsetDidChange(m_topContentInset);
931 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
933 if (suppressAnimations == m_suppressScrollbarAnimations)
936 lockAllOverlayScrollbarsToHidden(suppressAnimations);
937 m_suppressScrollbarAnimations = suppressAnimations;
940 void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars)
942 FrameView* view = mainFrame().view();
946 view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
948 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
949 FrameView* frameView = frame->view();
953 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
954 if (!scrollableAreas)
957 for (auto& scrollableArea : *scrollableAreas)
958 scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
962 void Page::setVerticalScrollElasticity(ScrollElasticity elasticity)
964 if (m_verticalScrollElasticity == elasticity)
967 m_verticalScrollElasticity = elasticity;
969 if (FrameView* view = mainFrame().view())
970 view->setVerticalScrollElasticity(elasticity);
973 void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity)
975 if (m_horizontalScrollElasticity == elasticity)
978 m_horizontalScrollElasticity = elasticity;
980 if (FrameView* view = mainFrame().view())
981 view->setHorizontalScrollElasticity(elasticity);
984 void Page::setPagination(const Pagination& pagination)
986 if (m_pagination == pagination)
989 m_pagination = pagination;
991 setNeedsRecalcStyleInAllFrames();
994 void Page::setPaginationLineGridEnabled(bool enabled)
996 if (m_paginationLineGridEnabled == enabled)
999 m_paginationLineGridEnabled = enabled;
1001 setNeedsRecalcStyleInAllFrames();
1004 unsigned Page::pageCount() const
1006 if (m_pagination.mode == Pagination::Unpaginated)
1009 if (Document* document = mainFrame().document())
1010 document->updateLayoutIgnorePendingStylesheets();
1012 RenderView* contentRenderer = mainFrame().contentRenderer();
1013 return contentRenderer ? contentRenderer->pageCount() : 0;
1016 void Page::setIsInWindow(bool isInWindow)
1018 setActivityState(isInWindow ? m_activityState | ActivityState::IsInWindow : m_activityState & ~ActivityState::IsInWindow);
1021 void Page::setIsInWindowInternal(bool isInWindow)
1023 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1024 if (FrameView* frameView = frame->view())
1025 frameView->setIsInWindow(isInWindow);
1029 resumeAnimatingImages();
1032 void Page::addActivityStateChangeObserver(ActivityStateChangeObserver& observer)
1034 m_activityStateChangeObservers.add(&observer);
1037 void Page::removeActivityStateChangeObserver(ActivityStateChangeObserver& observer)
1039 m_activityStateChangeObservers.remove(&observer);
1042 void Page::suspendScriptedAnimations()
1044 m_scriptedAnimationsSuspended = true;
1045 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1046 if (frame->document())
1047 frame->document()->suspendScriptedAnimationControllerCallbacks();
1051 void Page::resumeScriptedAnimations()
1053 m_scriptedAnimationsSuspended = false;
1054 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1055 if (frame->document())
1056 frame->document()->resumeScriptedAnimationControllerCallbacks();
1060 void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
1062 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1063 if (frame->document())
1064 frame->document()->scriptedAnimationControllerSetThrottled(isVisuallyIdle);
1068 void Page::userStyleSheetLocationChanged()
1070 // FIXME: Eventually we will move to a model of just being handed the sheet
1071 // text instead of loading the URL ourselves.
1072 URL url = m_settings->userStyleSheetLocation();
1074 // Allow any local file URL scheme to be loaded.
1075 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol().toStringWithoutCopying()))
1076 m_userStyleSheetPath = url.fileSystemPath();
1078 m_userStyleSheetPath = String();
1080 m_didLoadUserStyleSheet = false;
1081 m_userStyleSheet = String();
1082 m_userStyleSheetModificationTime = 0;
1084 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
1085 // synchronously and avoid using a loader.
1086 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
1087 m_didLoadUserStyleSheet = true;
1089 Vector<char> styleSheetAsUTF8;
1090 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreSpacesAndNewLines))
1091 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
1094 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1095 if (frame->document())
1096 frame->document()->extensionStyleSheets().updatePageUserSheet();
1100 const String& Page::userStyleSheet() const
1102 if (m_userStyleSheetPath.isEmpty())
1103 return m_userStyleSheet;
1106 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
1107 // The stylesheet either doesn't exist, was just deleted, or is
1108 // otherwise unreadable. If we've read the stylesheet before, we should
1109 // throw away that data now as it no longer represents what's on disk.
1110 m_userStyleSheet = String();
1111 return m_userStyleSheet;
1114 // If the stylesheet hasn't changed since the last time we read it, we can
1115 // just return the old data.
1116 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
1117 return m_userStyleSheet;
1119 m_didLoadUserStyleSheet = true;
1120 m_userStyleSheet = String();
1121 m_userStyleSheetModificationTime = modTime;
1123 // FIXME: It would be better to load this asynchronously to avoid blocking
1124 // the process, but we will first need to create an asynchronous loading
1125 // mechanism that is not tied to a particular Frame. We will also have to
1126 // determine what our behavior should be before the stylesheet is loaded
1127 // and what should happen when it finishes loading, especially with respect
1128 // to when the load event fires, when Document::close is called, and when
1129 // layout/paint are allowed to happen.
1130 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
1132 return m_userStyleSheet;
1134 m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size());
1136 return m_userStyleSheet;
1139 void Page::invalidateStylesForAllLinks()
1141 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1142 if (!frame->document())
1144 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
1148 void Page::invalidateStylesForLink(LinkHash linkHash)
1150 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1151 if (!frame->document())
1153 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
1157 void Page::invalidateInjectedStyleSheetCacheInAllFrames()
1159 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
1160 Document* document = frame->document();
1163 document->extensionStyleSheets().invalidateInjectedStyleSheetCache();
1167 void Page::setDebugger(JSC::Debugger* debugger)
1169 if (m_debugger == debugger)
1172 m_debugger = debugger;
1174 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1175 frame->script().attachDebugger(m_debugger);
1178 StorageNamespace* Page::sessionStorage(bool optionalCreate)
1180 if (!m_sessionStorage && optionalCreate)
1181 m_sessionStorage = m_storageNamespaceProvider->createSessionStorageNamespace(*this, m_settings->sessionStorageQuota());
1183 return m_sessionStorage.get();
1186 void Page::setSessionStorage(RefPtr<StorageNamespace>&& newStorage)
1188 m_sessionStorage = WTFMove(newStorage);
1191 bool Page::hasCustomHTMLTokenizerTimeDelay() const
1193 return m_settings->maxParseDuration() != -1;
1196 double Page::customHTMLTokenizerTimeDelay() const
1198 ASSERT(m_settings->maxParseDuration() != -1);
1199 return m_settings->maxParseDuration();
1202 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1204 if (m_areMemoryCacheClientCallsEnabled == enabled)
1207 m_areMemoryCacheClientCallsEnabled = enabled;
1211 for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1212 frame->loader().tellClientAboutPastMemoryCacheLoads();
1215 void Page::hiddenPageDOMTimerThrottlingStateChanged()
1217 // Disable & reengage to ensure state is updated.
1218 setTimerThrottlingState(TimerThrottlingState::Disabled);
1219 updateTimerThrottlingState();
1222 void Page::updateTimerThrottlingState()
1224 // Timer throttling disabled if page is visually active, or disabled by setting.
1225 if (!m_settings->hiddenPageDOMTimerThrottlingEnabled() || !(m_activityState & ActivityState::IsVisuallyIdle)) {
1226 setTimerThrottlingState(TimerThrottlingState::Disabled);
1230 // If the page is visible (but idle), there is any activity (loading, media playing, etc), or per setting,
1231 // we allow timer throttling, but not increasing timer throttling.
1232 if (!m_settings->hiddenPageDOMTimerThrottlingAutoIncreases()
1233 || m_activityState & (ActivityState::IsVisible | ActivityState::IsAudible | ActivityState::IsLoading)) {
1234 setTimerThrottlingState(TimerThrottlingState::Enabled);
1238 // If we get here increasing timer throttling is enabled.
1239 setTimerThrottlingState(TimerThrottlingState::EnabledIncreasing);
1242 void Page::setTimerThrottlingState(TimerThrottlingState state)
1244 if (state == m_timerThrottlingState)
1247 m_timerThrottlingState = state;
1248 m_timerThrottlingStateLastChangedTime = std::chrono::steady_clock::now();
1250 updateDOMTimerAlignmentInterval();
1252 // When throttling is disabled, release all throttled timers.
1253 if (state == TimerThrottlingState::Disabled) {
1254 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1255 if (auto* document = frame->document())
1256 document->didChangeTimerAlignmentInterval();
1261 void Page::setTimerAlignmentIntervalIncreaseLimit(std::chrono::milliseconds limit)
1263 m_timerAlignmentIntervalIncreaseLimit = limit;
1265 // If (m_timerAlignmentIntervalIncreaseLimit < m_timerAlignmentInterval) then we need
1266 // to update m_timerAlignmentInterval, if greater then need to restart the increase timer.
1267 if (m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing)
1268 updateDOMTimerAlignmentInterval();
1271 void Page::updateDOMTimerAlignmentInterval()
1273 bool needsIncreaseTimer = false;
1275 switch (m_timerThrottlingState) {
1276 case TimerThrottlingState::Disabled:
1277 m_timerAlignmentInterval = DOMTimer::defaultAlignmentInterval();
1280 case TimerThrottlingState::Enabled:
1281 m_timerAlignmentInterval = DOMTimer::hiddenPageAlignmentInterval();
1284 case TimerThrottlingState::EnabledIncreasing:
1285 // For pages in prerender state maximum throttling kicks in immediately.
1287 m_timerAlignmentInterval = m_timerAlignmentIntervalIncreaseLimit;
1289 ASSERT(m_timerThrottlingStateLastChangedTime.time_since_epoch() != std::chrono::steady_clock::duration::zero());
1290 m_timerAlignmentInterval = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_timerThrottlingStateLastChangedTime);
1291 // If we're below the limit, set the timer. If above, clamp to limit.
1292 if (m_timerAlignmentInterval < m_timerAlignmentIntervalIncreaseLimit)
1293 needsIncreaseTimer = true;
1295 m_timerAlignmentInterval = m_timerAlignmentIntervalIncreaseLimit;
1297 // Alignment interval should not be less than DOMTimer::hiddenPageAlignmentInterval().
1298 m_timerAlignmentInterval = std::max(m_timerAlignmentInterval, DOMTimer::hiddenPageAlignmentInterval());
1301 // If throttling is enabled, auto-increasing of throttling is enabled, and the auto-increase
1302 // limit has not yet been reached, and then arm the timer to consider an increase. Time to wait
1303 // between increases is equal to the current throttle time. Since alinment interval increases
1304 // exponentially, time between steps is exponential too.
1305 if (!needsIncreaseTimer)
1306 m_timerAlignmentIntervalIncreaseTimer.stop();
1307 else if (!m_timerAlignmentIntervalIncreaseTimer.isActive())
1308 m_timerAlignmentIntervalIncreaseTimer.startOneShot(m_timerAlignmentInterval);
1311 void Page::timerAlignmentIntervalIncreaseTimerFired()
1313 ASSERT(m_settings->hiddenPageDOMTimerThrottlingAutoIncreases());
1314 ASSERT(m_timerThrottlingState == TimerThrottlingState::EnabledIncreasing);
1315 ASSERT(m_timerAlignmentInterval < m_timerAlignmentIntervalIncreaseLimit);
1317 // Alignment interval is increased to equal the time the page has been throttled, to a limit.
1318 updateDOMTimerAlignmentInterval();
1321 void Page::dnsPrefetchingStateChanged()
1323 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1324 if (!frame->document())
1326 frame->document()->initDNSPrefetch();
1330 Vector<Ref<PluginViewBase>> Page::pluginViews()
1332 Vector<Ref<PluginViewBase>> views;
1334 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1335 FrameView* view = frame->view();
1339 for (auto& widget : view->children()) {
1340 if (is<PluginViewBase>(*widget))
1341 views.append(downcast<PluginViewBase>(*widget));
1348 void Page::storageBlockingStateChanged()
1350 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1351 if (!frame->document())
1353 frame->document()->storageBlockingStateDidChange();
1356 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1357 // from below storageBlockingStateChanged does not affect their lifetime.
1358 for (auto& view : pluginViews())
1359 view->storageBlockingStateChanged();
1362 void Page::enableLegacyPrivateBrowsing(bool privateBrowsingEnabled)
1364 // Don't allow changing the legacy private browsing state if we have set a session ID.
1365 ASSERT(m_sessionID == SessionID::defaultSessionID() || m_sessionID == SessionID::legacyPrivateSessionID());
1367 setSessionID(privateBrowsingEnabled ? SessionID::legacyPrivateSessionID() : SessionID::defaultSessionID());
1370 void Page::updateIsPlayingMedia(uint64_t sourceElementID)
1372 MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
1373 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1374 if (Document* document = frame->document())
1375 state |= document->mediaState();
1378 if (state == m_mediaState)
1381 m_mediaState = state;
1383 chrome().client().isPlayingMediaDidChange(state, sourceElementID);
1386 void Page::setMuted(MediaProducer::MutedStateFlags muted)
1388 if (m_mutedState == muted)
1391 m_mutedState = muted;
1393 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1394 if (!frame->document())
1396 frame->document()->pageMutedStateDidChange();
1400 #if ENABLE(MEDIA_SESSION)
1401 void Page::handleMediaEvent(MediaEventType eventType)
1403 switch (eventType) {
1404 case MediaEventType::PlayPause:
1405 MediaSessionManager::singleton().togglePlayback();
1407 case MediaEventType::TrackNext:
1408 MediaSessionManager::singleton().skipToNextTrack();
1410 case MediaEventType::TrackPrevious:
1411 MediaSessionManager::singleton().skipToPreviousTrack();
1416 void Page::setVolumeOfMediaElement(double volume, uint64_t elementID)
1418 if (HTMLMediaElement* element = HTMLMediaElement::elementWithID(elementID))
1419 element->setVolume(volume, ASSERT_NO_EXCEPTION);
1423 #if !ASSERT_DISABLED
1424 void Page::checkSubframeCountConsistency() const
1426 ASSERT(m_subframeCount >= 0);
1428 int subframeCount = 0;
1429 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1432 ASSERT(m_subframeCount + 1 == subframeCount);
1436 void Page::resumeAnimatingImages()
1438 // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.)
1439 // require that we repaint animated images to kickstart the animation loop.
1440 if (FrameView* view = mainFrame().view())
1441 view->resumeVisibleImageAnimationsIncludingSubframes();
1444 void Page::setActivityState(ActivityState::Flags activityState)
1446 ActivityState::Flags changed = m_activityState ^ activityState;
1450 ActivityState::Flags oldActivityState = m_activityState;
1452 bool wasVisibleAndActive = isVisibleAndActive();
1453 m_activityState = activityState;
1455 m_focusController->setActivityState(activityState);
1457 if (changed & ActivityState::IsVisible)
1458 setIsVisibleInternal(activityState & ActivityState::IsVisible);
1459 if (changed & ActivityState::IsInWindow)
1460 setIsInWindowInternal(activityState & ActivityState::IsInWindow);
1461 if (changed & ActivityState::IsVisuallyIdle)
1462 setIsVisuallyIdleInternal(activityState & ActivityState::IsVisuallyIdle);
1464 if (changed & (ActivityState::IsVisible | ActivityState::IsVisuallyIdle | ActivityState::IsAudible | ActivityState::IsLoading))
1465 updateTimerThrottlingState();
1467 for (auto* observer : m_activityStateChangeObservers)
1468 observer->activityStateDidChange(oldActivityState, m_activityState);
1470 if (wasVisibleAndActive != isVisibleAndActive())
1471 PlatformMediaSessionManager::updateNowPlayingInfoIfNecessary();
1474 bool Page::isVisibleAndActive() const
1476 return (m_activityState & ActivityState::IsVisible) && (m_activityState & ActivityState::WindowIsActive);
1479 void Page::setIsVisible(bool isVisible)
1482 setActivityState((m_activityState & ~ActivityState::IsVisuallyIdle) | ActivityState::IsVisible | ActivityState::IsVisibleOrOccluded);
1484 setActivityState((m_activityState & ~(ActivityState::IsVisible | ActivityState::IsVisibleOrOccluded)) | ActivityState::IsVisuallyIdle);
1487 void Page::setIsVisibleInternal(bool isVisible)
1489 // FIXME: The visibility state should be stored on the top-level document.
1490 // https://bugs.webkit.org/show_bug.cgi?id=116769
1493 m_isPrerender = false;
1495 resumeScriptedAnimations();
1497 resumeDeviceMotionAndOrientationUpdates();
1500 if (FrameView* view = mainFrame().view())
1503 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1504 mainFrame().animation().resumeAnimations();
1506 resumeAnimatingImages();
1509 Vector<Ref<Document>> documents;
1510 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1511 documents.append(*frame->document());
1513 for (auto& document : documents)
1514 document->visibilityStateChanged();
1517 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1518 mainFrame().animation().suspendAnimations();
1521 suspendDeviceMotionAndOrientationUpdates();
1523 suspendScriptedAnimations();
1525 if (FrameView* view = mainFrame().view())
1530 void Page::setIsPrerender()
1532 m_isPrerender = true;
1533 updateDOMTimerAlignmentInterval();
1536 PageVisibilityState Page::visibilityState() const
1539 return PageVisibilityStateVisible;
1541 return PageVisibilityStatePrerender;
1542 return PageVisibilityStateHidden;
1545 #if ENABLE(RUBBER_BANDING)
1546 void Page::addHeaderWithHeight(int headerHeight)
1548 m_headerHeight = headerHeight;
1550 FrameView* frameView = mainFrame().view();
1554 RenderView* renderView = frameView->renderView();
1558 frameView->setHeaderHeight(m_headerHeight);
1559 renderView->compositor().updateLayerForHeader(m_headerHeight);
1562 void Page::addFooterWithHeight(int footerHeight)
1564 m_footerHeight = footerHeight;
1566 FrameView* frameView = mainFrame().view();
1570 RenderView* renderView = frameView->renderView();
1574 frameView->setFooterHeight(m_footerHeight);
1575 renderView->compositor().updateLayerForFooter(m_footerHeight);
1579 #if ENABLE(REMOTE_INSPECTOR)
1580 bool Page::remoteInspectionAllowed() const
1582 return m_inspectorDebuggable->remoteDebuggingAllowed();
1585 void Page::setRemoteInspectionAllowed(bool allowed)
1587 m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed);
1590 String Page::remoteInspectionNameOverride() const
1592 return m_inspectorDebuggable->nameOverride();
1595 void Page::setRemoteInspectionNameOverride(const String& name)
1597 m_inspectorDebuggable->setNameOverride(name);
1600 void Page::remoteInspectorInformationDidChange() const
1602 m_inspectorDebuggable->update();
1606 void Page::addLayoutMilestones(LayoutMilestones milestones)
1608 // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
1609 m_requestedLayoutMilestones |= milestones;
1612 void Page::removeLayoutMilestones(LayoutMilestones milestones)
1614 m_requestedLayoutMilestones &= ~milestones;
1617 Color Page::pageExtendedBackgroundColor() const
1619 FrameView* frameView = mainFrame().view();
1623 RenderView* renderView = frameView->renderView();
1627 return renderView->compositor().rootExtendedBackgroundColor();
1630 // These are magical constants that might be tweaked over time.
1631 static const double gMinimumPaintedAreaRatio = 0.1;
1632 static const double gMaximumUnpaintedAreaRatio = 0.04;
1634 bool Page::isCountingRelevantRepaintedObjects() const
1636 return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold);
1639 void Page::startCountingRelevantRepaintedObjects()
1641 // Reset everything in case we didn't hit the threshold last time.
1642 resetRelevantPaintedObjectCounter();
1644 m_isCountingRelevantRepaintedObjects = true;
1647 void Page::resetRelevantPaintedObjectCounter()
1649 m_isCountingRelevantRepaintedObjects = false;
1650 m_relevantUnpaintedRenderObjects.clear();
1651 m_topRelevantPaintedRegion = Region();
1652 m_bottomRelevantPaintedRegion = Region();
1653 m_relevantUnpaintedRegion = Region();
1656 static LayoutRect relevantViewRect(RenderView* view)
1658 // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
1659 // a certain relevant amount of content has been drawn to the screen. This is the rect that
1660 // has been determined to be relevant in the context of this goal. We may choose to tweak
1661 // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
1662 // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
1663 LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);
1665 LayoutRect viewRect = view->viewRect();
1666 // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
1667 if (viewRect.width() > relevantViewRect.width())
1668 relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
1670 return relevantViewRect;
1673 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1675 if (!isCountingRelevantRepaintedObjects())
1678 // Objects inside sub-frames are not considered to be relevant.
1679 if (&object->frame() != &mainFrame())
1682 LayoutRect relevantRect = relevantViewRect(&object->view());
1684 // The objects are only relevant if they are being painted within the viewRect().
1685 if (!objectPaintRect.intersects(snappedIntRect(relevantRect)))
1688 IntRect snappedPaintRect = snappedIntRect(objectPaintRect);
1690 // If this object was previously counted as an unpainted object, remove it from that HashSet
1691 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
1692 if (m_relevantUnpaintedRenderObjects.remove(object))
1693 m_relevantUnpaintedRegion.subtract(snappedPaintRect);
1695 // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
1696 // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
1697 // no content beneath that.
1698 LayoutRect topRelevantRect = relevantRect;
1699 topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2));
1700 LayoutRect bottomRelevantRect = topRelevantRect;
1701 bottomRelevantRect.setY(relevantRect.height() / 2);
1703 // If the rect straddles both Regions, split it appropriately.
1704 if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
1705 IntRect topIntersection = snappedPaintRect;
1706 topIntersection.intersect(snappedIntRect(topRelevantRect));
1707 m_topRelevantPaintedRegion.unite(topIntersection);
1709 IntRect bottomIntersection = snappedPaintRect;
1710 bottomIntersection.intersect(snappedIntRect(bottomRelevantRect));
1711 m_bottomRelevantPaintedRegion.unite(bottomIntersection);
1712 } else if (topRelevantRect.intersects(snappedPaintRect))
1713 m_topRelevantPaintedRegion.unite(snappedPaintRect);
1715 m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
1717 float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
1718 float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
1719 float viewArea = relevantRect.width() * relevantRect.height();
1721 float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
1722 float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
1723 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1725 if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
1726 && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1727 m_isCountingRelevantRepaintedObjects = false;
1728 resetRelevantPaintedObjectCounter();
1729 if (Frame* frame = &mainFrame())
1730 frame->loader().didReachLayoutMilestone(DidHitRelevantRepaintedObjectsAreaThreshold);
1734 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1736 if (!isCountingRelevantRepaintedObjects())
1739 // The objects are only relevant if they are being painted within the relevantViewRect().
1740 if (!objectPaintRect.intersects(snappedIntRect(relevantViewRect(&object->view()))))
1743 m_relevantUnpaintedRenderObjects.add(object);
1744 m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect));
1747 void Page::suspendDeviceMotionAndOrientationUpdates()
1749 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1750 if (Document* document = frame->document())
1751 document->suspendDeviceMotionAndOrientationUpdates();
1755 void Page::resumeDeviceMotionAndOrientationUpdates()
1757 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1758 if (Document* document = frame->document())
1759 document->resumeDeviceMotionAndOrientationUpdates();
1763 void Page::suspendActiveDOMObjectsAndAnimations()
1765 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1766 frame->suspendActiveDOMObjectsAndAnimations();
1769 void Page::resumeActiveDOMObjectsAndAnimations()
1771 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1772 frame->resumeActiveDOMObjectsAndAnimations();
1774 resumeAnimatingImages();
1777 bool Page::hasSeenAnyPlugin() const
1779 return !m_seenPlugins.isEmpty();
1782 bool Page::hasSeenPlugin(const String& serviceType) const
1784 return m_seenPlugins.contains(serviceType);
1787 void Page::sawPlugin(const String& serviceType)
1789 m_seenPlugins.add(serviceType);
1792 void Page::resetSeenPlugins()
1794 m_seenPlugins.clear();
1797 bool Page::hasSeenAnyMediaEngine() const
1799 return !m_seenMediaEngines.isEmpty();
1802 bool Page::hasSeenMediaEngine(const String& engineDescription) const
1804 return m_seenMediaEngines.contains(engineDescription);
1807 void Page::sawMediaEngine(const String& engineDescription)
1809 m_seenMediaEngines.add(engineDescription);
1812 void Page::resetSeenMediaEngines()
1814 m_seenMediaEngines.clear();
1817 void Page::hiddenPageCSSAnimationSuspensionStateChanged()
1820 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1821 mainFrame().animation().suspendAnimations();
1823 mainFrame().animation().resumeAnimations();
1827 #if ENABLE(VIDEO_TRACK)
1828 void Page::captionPreferencesChanged()
1830 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1831 if (!frame->document())
1833 frame->document()->captionPreferencesChanged();
1838 void Page::forbidPrompts()
1840 ++m_forbidPromptsDepth;
1843 void Page::allowPrompts()
1845 ASSERT(m_forbidPromptsDepth);
1846 --m_forbidPromptsDepth;
1849 bool Page::arePromptsAllowed()
1851 return !m_forbidPromptsDepth;
1854 PluginInfoProvider& Page::pluginInfoProvider()
1856 return m_pluginInfoProvider;
1859 UserContentProvider& Page::userContentProvider()
1861 return m_userContentProvider;
1864 void Page::setUserContentProvider(Ref<UserContentProvider>&& userContentProvider)
1866 m_userContentProvider->removePage(*this);
1867 m_userContentProvider = WTFMove(userContentProvider);
1868 m_userContentProvider->addPage(*this);
1870 invalidateInjectedStyleSheetCacheInAllFrames();
1873 void Page::setStorageNamespaceProvider(Ref<StorageNamespaceProvider>&& storageNamespaceProvider)
1875 m_storageNamespaceProvider->removePage(*this);
1876 m_storageNamespaceProvider = WTFMove(storageNamespaceProvider);
1877 m_storageNamespaceProvider->addPage(*this);
1879 // This needs to reset all the local storage namespaces of all the pages.
1882 VisitedLinkStore& Page::visitedLinkStore()
1884 return m_visitedLinkStore;
1887 void Page::setVisitedLinkStore(Ref<VisitedLinkStore>&& visitedLinkStore)
1889 m_visitedLinkStore->removePage(*this);
1890 m_visitedLinkStore = WTFMove(visitedLinkStore);
1891 m_visitedLinkStore->addPage(*this);
1893 invalidateStylesForAllLinks();
1896 SessionID Page::sessionID() const
1901 void Page::setSessionID(SessionID sessionID)
1903 ASSERT(sessionID.isValid());
1905 #if ENABLE(INDEXED_DATABASE)
1906 if (sessionID != m_sessionID)
1907 m_idbIDBConnectionToServer = nullptr;
1910 bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral());
1912 m_sessionID = sessionID;
1914 if (!privateBrowsingStateChanged)
1917 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1918 if (!frame->document())
1920 frame->document()->privateBrowsingStateDidChange();
1923 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1924 // from below privateBrowsingStateChanged does not affect their lifetime.
1926 for (auto& view : pluginViews())
1927 view->privateBrowsingStateChanged(sessionID.isEphemeral());
1930 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1931 void Page::addPlaybackTargetPickerClient(uint64_t contextId)
1933 chrome().client().addPlaybackTargetPickerClient(contextId);
1936 void Page::removePlaybackTargetPickerClient(uint64_t contextId)
1938 chrome().client().removePlaybackTargetPickerClient(contextId);
1941 void Page::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool isVideo)
1944 // FIXME: refactor iOS implementation.
1945 UNUSED_PARAM(contextId);
1946 UNUSED_PARAM(location);
1947 chrome().client().showPlaybackTargetPicker(isVideo);
1949 chrome().client().showPlaybackTargetPicker(contextId, location, isVideo);
1953 void Page::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
1955 chrome().client().playbackTargetPickerClientStateDidChange(contextId, state);
1958 void Page::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
1960 chrome().client().setMockMediaPlaybackTargetPickerEnabled(enabled);
1963 void Page::setMockMediaPlaybackTargetPickerState(const String& name, MediaPlaybackTargetContext::State state)
1965 chrome().client().setMockMediaPlaybackTargetPickerState(name, state);
1968 void Page::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target)
1970 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1971 if (!frame->document())
1973 frame->document()->setPlaybackTarget(contextId, target.copyRef());
1977 void Page::playbackTargetAvailabilityDidChange(uint64_t contextId, bool available)
1979 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1980 if (!frame->document())
1982 frame->document()->playbackTargetAvailabilityDidChange(contextId, available);
1986 void Page::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay)
1988 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1989 if (!frame->document())
1991 frame->document()->setShouldPlayToPlaybackTarget(clientId, shouldPlay);
1996 WheelEventTestTrigger& Page::ensureTestTrigger()
1999 m_testTrigger = adoptRef(new WheelEventTestTrigger());
2001 return *m_testTrigger;
2005 void Page::setAllowsMediaDocumentInlinePlayback(bool flag)
2007 if (m_allowsMediaDocumentInlinePlayback == flag)
2009 m_allowsMediaDocumentInlinePlayback = flag;
2011 Vector<Ref<Document>> documents;
2012 for (Frame* frame = &m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
2013 documents.append(*frame->document());
2015 for (auto& document : documents)
2016 document->allowsMediaDocumentInlinePlaybackChanged();
2020 #if ENABLE(INDEXED_DATABASE)
2021 IDBClient::IDBConnectionToServer& Page::idbConnection()
2023 if (!m_idbIDBConnectionToServer)
2024 m_idbIDBConnectionToServer = &databaseProvider().idbConnectionToServerForSession(m_sessionID);
2026 return *m_idbIDBConnectionToServer;
2030 #if ENABLE(RESOURCE_USAGE)
2031 void Page::setResourceUsageOverlayVisible(bool visible)
2034 m_resourceUsageOverlay = nullptr;
2038 if (!m_resourceUsageOverlay)
2039 m_resourceUsageOverlay = std::make_unique<ResourceUsageOverlay>(*this);
2043 bool Page::isAlwaysOnLoggingAllowed() const
2045 return m_sessionID.isAlwaysOnLoggingAllowed();
2048 String Page::captionUserPreferencesStyleSheet()
2050 return m_captionUserPreferencesStyleSheet;
2053 void Page::setCaptionUserPreferencesStyleSheet(const String& styleSheet)
2055 if (m_captionUserPreferencesStyleSheet == styleSheet)
2058 m_captionUserPreferencesStyleSheet = styleSheet;
2060 invalidateInjectedStyleSheetCacheInAllFrames();
2063 } // namespace WebCore