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 "AlternativeTextClient.h"
24 #include "AnimationController.h"
25 #include "ApplicationCacheStorage.h"
26 #include "BackForwardClient.h"
27 #include "BackForwardController.h"
29 #include "ChromeClient.h"
30 #include "ClientRectList.h"
31 #include "ContextMenuClient.h"
32 #include "ContextMenuController.h"
33 #include "DatabaseProvider.h"
34 #include "DocumentLoader.h"
35 #include "DocumentMarkerController.h"
36 #include "DocumentStyleSheetCollection.h"
37 #include "DragController.h"
39 #include "EditorClient.h"
41 #include "EventNames.h"
42 #include "ExceptionCode.h"
43 #include "ExceptionCodePlaceholder.h"
44 #include "FileSystem.h"
45 #include "FocusController.h"
46 #include "FrameLoader.h"
47 #include "FrameLoaderClient.h"
48 #include "FrameSelection.h"
49 #include "FrameTree.h"
50 #include "FrameView.h"
51 #include "HTMLElement.h"
52 #include "HistoryController.h"
53 #include "HistoryItem.h"
54 #include "InspectorController.h"
55 #include "InspectorInstrumentation.h"
57 #include "MainFrame.h"
58 #include "MediaCanStartListener.h"
59 #include "Navigator.h"
60 #include "NetworkStateNotifier.h"
61 #include "PageCache.h"
62 #include "PageConfiguration.h"
63 #include "PageConsoleClient.h"
64 #include "PageDebuggable.h"
65 #include "PageGroup.h"
66 #include "PageOverlayController.h"
67 #include "PageThrottler.h"
68 #include "PlugInClient.h"
69 #include "PluginData.h"
70 #include "PluginViewBase.h"
71 #include "PointerLockController.h"
72 #include "ProgressTracker.h"
73 #include "RenderLayerCompositor.h"
74 #include "RenderTheme.h"
75 #include "RenderView.h"
76 #include "RenderWidget.h"
77 #include "RuntimeEnabledFeatures.h"
78 #include "SchemeRegistry.h"
79 #include "ScriptController.h"
80 #include "ScrollingCoordinator.h"
82 #include "SharedBuffer.h"
83 #include "StorageArea.h"
84 #include "StorageNamespace.h"
85 #include "StorageNamespaceProvider.h"
86 #include "StyleResolver.h"
87 #include "SubframeLoader.h"
88 #include "TextResourceDecoder.h"
89 #include "UserContentController.h"
90 #include "UserInputBridge.h"
91 #include "ViewStateChangeObserver.h"
92 #include "VisitedLinkState.h"
93 #include "VisitedLinkStore.h"
94 #include "VoidCallback.h"
96 #include <JavaScriptCore/Profile.h>
97 #include <wtf/HashMap.h>
98 #include <wtf/RefCountedLeakCounter.h>
99 #include <wtf/StdLibExtras.h>
100 #include <wtf/text/Base64.h>
101 #include <wtf/text/StringHash.h>
103 #if ENABLE(WEB_REPLAY)
104 #include "ReplayController.h"
105 #include <replay/InputCursor.h>
108 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
109 #include "HTMLVideoElement.h"
110 #include "MediaPlaybackTarget.h"
115 static HashSet<Page*>* allPages;
117 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
119 static void networkStateChanged(bool isOnLine)
121 Vector<Ref<Frame>> frames;
123 // Get all the frames of all the pages in all the page groups
124 for (auto& page : *allPages) {
125 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
126 frames.append(*frame);
127 InspectorInstrumentation::networkStateChanged(page);
130 AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent;
131 for (auto& frame : frames)
132 frame->document()->dispatchWindowEvent(Event::create(eventName, false, false));
135 static const ViewState::Flags PageInitialViewState = ViewState::IsVisible | ViewState::IsInWindow;
137 Page::Page(PageConfiguration& pageConfiguration)
138 : m_chrome(std::make_unique<Chrome>(*this, *pageConfiguration.chromeClient))
139 , m_dragCaretController(std::make_unique<DragCaretController>())
140 #if ENABLE(DRAG_SUPPORT)
141 , m_dragController(std::make_unique<DragController>(*this, *pageConfiguration.dragClient))
143 , m_focusController(std::make_unique<FocusController>(*this, PageInitialViewState))
144 #if ENABLE(CONTEXT_MENUS)
145 , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageConfiguration.contextMenuClient))
147 , m_userInputBridge(std::make_unique<UserInputBridge>(*this))
148 #if ENABLE(WEB_REPLAY)
149 , m_replayController(std::make_unique<ReplayController>(*this))
151 , m_inspectorController(std::make_unique<InspectorController>(*this, pageConfiguration.inspectorClient))
152 #if ENABLE(POINTER_LOCK)
153 , m_pointerLockController(std::make_unique<PointerLockController>(*this))
155 , m_settings(Settings::create(this))
156 , m_progress(std::make_unique<ProgressTracker>(*pageConfiguration.progressTrackerClient))
157 , m_backForwardController(std::make_unique<BackForwardController>(*this, pageConfiguration.backForwardClient))
158 , m_mainFrame(MainFrame::create(*this, pageConfiguration))
159 , m_theme(RenderTheme::themeForPage(this))
160 , m_editorClient(*pageConfiguration.editorClient)
161 , m_plugInClient(pageConfiguration.plugInClient)
162 , m_validationMessageClient(pageConfiguration.validationMessageClient)
164 , m_openedByDOM(false)
165 , m_tabKeyCyclesThroughElements(true)
166 , m_defersLoading(false)
167 , m_defersLoadingCallCount(0)
168 , m_inLowQualityInterpolationMode(false)
169 , m_areMemoryCacheClientCallsEnabled(true)
172 , m_pageScaleFactor(1)
173 , m_zoomedOutPageScaleFactor(0)
174 , m_deviceScaleFactor(1)
175 , m_topContentInset(0)
176 #if ENABLE(IOS_TEXT_AUTOSIZING)
177 , m_textAutosizingWidth(0)
179 , m_suppressScrollbarAnimations(false)
180 , m_verticalScrollElasticity(ScrollElasticityAllowed)
181 , m_horizontalScrollElasticity(ScrollElasticityAllowed)
182 , m_didLoadUserStyleSheet(false)
183 , m_userStyleSheetModificationTime(0)
185 , m_debugger(nullptr)
186 , m_canStartMedia(true)
187 #if ENABLE(VIEW_MODE_CSS_MEDIA)
188 , m_viewMode(ViewModeWindowed)
189 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
190 , m_timerThrottlingEnabled(false)
191 , m_isEditable(false)
192 , m_isPrerender(false)
193 , m_viewState(PageInitialViewState)
194 , m_requestedLayoutMilestones(0)
197 , m_isCountingRelevantRepaintedObjects(false)
199 , m_isPainting(false)
201 , m_alternativeTextClient(pageConfiguration.alternativeTextClient)
202 , m_scriptedAnimationsSuspended(false)
203 , m_pageThrottler(*this)
204 , m_consoleClient(std::make_unique<PageConsoleClient>(*this))
205 #if ENABLE(REMOTE_INSPECTOR)
206 , m_inspectorDebuggable(std::make_unique<PageDebuggable>(*this))
208 , m_lastSpatialNavigationCandidatesCount(0) // NOTE: Only called from Internals for Spatial Navigation testing.
209 , m_framesHandlingBeforeUnloadEvent(0)
210 , m_applicationCacheStorage(pageConfiguration.applicationCacheStorage ? *WTF::move(pageConfiguration.applicationCacheStorage) : ApplicationCacheStorage::singleton())
211 , m_databaseProvider(*WTF::move(pageConfiguration.databaseProvider))
212 , m_storageNamespaceProvider(*WTF::move(pageConfiguration.storageNamespaceProvider))
213 , m_userContentController(WTF::move(pageConfiguration.userContentController))
214 , m_visitedLinkStore(*WTF::move(pageConfiguration.visitedLinkStore))
215 , m_sessionID(SessionID::defaultSessionID())
218 setTimerThrottlingEnabled(m_viewState & ViewState::IsVisuallyIdle);
220 m_storageNamespaceProvider->addPage(*this);
222 if (m_userContentController)
223 m_userContentController->addPage(*this);
225 m_visitedLinkStore->addPage(*this);
228 allPages = new HashSet<Page*>;
230 networkStateNotifier().addNetworkStateChangeListener(networkStateChanged);
233 ASSERT(!allPages->contains(this));
237 pageCounter.increment();
240 #if ENABLE(REMOTE_INSPECTOR)
241 m_inspectorDebuggable->init();
247 m_mainFrame->setView(nullptr);
248 setGroupName(String());
249 allPages->remove(this);
251 m_settings->pageDestroyed();
253 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
254 frame->willDetachPage();
255 frame->detachFromPage();
258 m_editorClient.pageDestroyed();
260 m_plugInClient->pageDestroyed();
261 if (m_alternativeTextClient)
262 m_alternativeTextClient->pageDestroyed();
264 m_inspectorController->inspectedPageDestroyed();
266 if (m_scrollingCoordinator)
267 m_scrollingCoordinator->pageDestroyed();
269 backForward().close();
272 pageCounter.decrement();
275 m_storageNamespaceProvider->removePage(*this);
277 if (m_userContentController)
278 m_userContentController->removePage(*this);
279 m_visitedLinkStore->removePage(*this);
282 std::unique_ptr<Page> Page::createPageFromBuffer(PageConfiguration& pageConfiguration, const SharedBuffer* buffer, const String& mimeType, bool canHaveScrollbars, bool transparent)
286 std::unique_ptr<Page> newPage = std::make_unique<Page>(pageConfiguration);
287 newPage->settings().setMediaEnabled(false);
288 newPage->settings().setScriptEnabled(false);
289 newPage->settings().setPluginsEnabled(false);
291 Frame& frame = newPage->mainFrame();
292 frame.setView(FrameView::create(frame));
294 FrameLoader& loader = frame.loader();
295 loader.forceSandboxFlags(SandboxAll);
297 frame.view()->setCanHaveScrollbars(canHaveScrollbars);
298 frame.view()->setTransparent(transparent);
300 ASSERT(loader.activeDocumentLoader()); // DocumentLoader should have been created by frame->init().
301 loader.activeDocumentLoader()->writer().setMIMEType(mimeType);
302 loader.activeDocumentLoader()->writer().begin(URL()); // create the empty document
303 loader.activeDocumentLoader()->writer().addData(buffer->data(), buffer->size());
304 loader.activeDocumentLoader()->writer().end();
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 rects = scrollingCoordinator->absoluteNonFastScrollableRegion().rects();
381 Vector<FloatQuad> quads(rects.size());
382 for (size_t i = 0; i < rects.size(); ++i)
383 quads[i] = FloatRect(rects[i]);
385 return ClientRectList::create(quads);
388 #if ENABLE(VIEW_MODE_CSS_MEDIA)
389 struct ViewModeInfo {
393 static const int viewModeMapSize = 5;
394 static const ViewModeInfo viewModeMap[viewModeMapSize] = {
395 {"windowed", Page::ViewModeWindowed},
396 {"floating", Page::ViewModeFloating},
397 {"fullscreen", Page::ViewModeFullscreen},
398 {"maximized", Page::ViewModeMaximized},
399 {"minimized", Page::ViewModeMinimized}
402 Page::ViewMode Page::stringToViewMode(const String& text)
404 for (auto& mode : viewModeMap) {
405 if (text == mode.name)
408 return Page::ViewModeInvalid;
411 void Page::setViewMode(ViewMode viewMode)
413 if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
416 m_viewMode = viewMode;
421 if (m_mainFrame->view())
422 m_mainFrame->view()->forceLayout();
424 if (m_mainFrame->document())
425 m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
427 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
429 bool Page::openedByDOM() const
431 return m_openedByDOM;
434 void Page::setOpenedByDOM()
436 m_openedByDOM = true;
439 void Page::goToItem(HistoryItem& item, FrameLoadType type)
441 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
442 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
443 Ref<HistoryItem> protector(item);
445 if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item))
446 m_mainFrame->loader().stopAllLoaders();
448 m_mainFrame->loader().history().goToItem(item, type);
451 void Page::setGroupName(const String& name)
453 if (m_group && !m_group->name().isEmpty()) {
454 ASSERT(m_group != m_singlePageGroup.get());
455 ASSERT(!m_singlePageGroup);
456 m_group->removePage(*this);
460 m_group = m_singlePageGroup.get();
462 m_singlePageGroup = nullptr;
463 m_group = PageGroup::pageGroup(name);
464 m_group->addPage(*this);
468 const String& Page::groupName() const
470 return m_group ? m_group->name() : nullAtom.string();
473 void Page::initGroup()
475 ASSERT(!m_singlePageGroup);
477 m_singlePageGroup = std::make_unique<PageGroup>(*this);
478 m_group = m_singlePageGroup.get();
481 void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment()
485 for (auto& page : *allPages) {
486 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
487 // If a change in the global environment has occurred, we need to
488 // make sure all the properties a recomputed, therefore we invalidate
489 // the properties cache.
490 if (StyleResolver* styleResolver = frame->document()->styleResolverIfExists())
491 styleResolver->invalidateMatchedPropertiesCache();
492 frame->document()->scheduleForcedStyleRecalc();
497 void Page::setNeedsRecalcStyleInAllFrames()
499 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
500 if (Document* document = frame->document())
501 document->styleResolverChanged(DeferRecalcStyle);
505 void Page::refreshPlugins(bool reload)
510 PluginData::refresh();
512 Vector<Ref<Frame>> framesNeedingReload;
514 for (auto& page : *allPages) {
515 page->m_pluginData.clear();
520 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
521 if (frame->loader().subframeLoader().containsPlugins())
522 framesNeedingReload.append(*frame);
526 for (auto& frame : framesNeedingReload)
527 frame->loader().reload();
530 PluginData& Page::pluginData() const
533 m_pluginData = PluginData::create(this);
534 return *m_pluginData;
537 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
539 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
540 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
546 void Page::setCanStartMedia(bool canStartMedia)
548 if (m_canStartMedia == canStartMedia)
551 m_canStartMedia = canStartMedia;
553 while (m_canStartMedia) {
554 MediaCanStartListener* listener = takeAnyMediaCanStartListener();
557 listener->mediaCanStart();
561 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
564 ? curr->tree().traverseNextWithWrap(wrapFlag)
565 : curr->tree().traversePreviousWithWrap(wrapFlag);
568 bool Page::findString(const String& target, FindOptions options)
570 if (target.isEmpty())
573 bool shouldWrap = options & WrapAround;
574 Frame* frame = &focusController().focusedOrMainFrame();
575 Frame* startFrame = frame;
577 if (frame->editor().findString(target, (options & ~WrapAround) | StartInSelection)) {
578 if (frame != startFrame)
579 startFrame->selection().clear();
580 focusController().setFocusedFrame(frame);
583 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
584 } while (frame && frame != startFrame);
586 // Search contents of startFrame, on the other side of the selection that we did earlier.
587 // We cheat a bit and just research with wrap on
588 if (shouldWrap && !startFrame->selection().isNone()) {
589 bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection);
590 focusController().setFocusedFrame(frame);
597 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>& matchRanges, int& indexForSelection)
599 indexForSelection = 0;
601 Frame* frame = &mainFrame();
602 Frame* frameWithSelection = nullptr;
604 frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges.size()) : 0, true, &matchRanges);
605 if (frame->selection().isRange())
606 frameWithSelection = frame;
607 frame = incrementFrame(frame, true, false);
610 if (matchRanges.isEmpty())
613 if (frameWithSelection) {
614 indexForSelection = NoMatchAfterUserSelection;
615 RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange();
616 if (options & Backwards) {
617 for (size_t i = matchRanges.size(); i > 0; --i) {
618 if (selectedRange->compareBoundaryPoints(Range::END_TO_START, matchRanges[i - 1].get(), IGNORE_EXCEPTION) > 0) {
619 indexForSelection = i - 1;
624 for (size_t i = 0, size = matchRanges.size(); i < size; ++i) {
625 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges[i].get(), IGNORE_EXCEPTION) < 0) {
626 indexForSelection = i;
632 if (options & Backwards)
633 indexForSelection = matchRanges.size() - 1;
635 indexForSelection = 0;
639 RefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
641 if (target.isEmpty())
644 if (referenceRange && referenceRange->ownerDocument().page() != this)
647 bool shouldWrap = options & WrapAround;
648 Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame();
649 Frame* startFrame = frame;
651 if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
654 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
655 } while (frame && frame != startFrame);
657 // Search contents of startFrame, on the other side of the reference range that we did earlier.
658 // We cheat a bit and just search again with wrap on.
659 if (shouldWrap && referenceRange) {
660 if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
667 unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches)
669 if (target.isEmpty())
672 unsigned matchCount = 0;
674 Frame* frame = &mainFrame();
676 if (shouldMarkMatches == MarkMatches)
677 frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches);
678 matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0);
679 frame = incrementFrame(frame, true, false);
685 unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount)
687 return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches);
690 unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount)
692 return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches);
695 void Page::unmarkAllTextMatches()
697 Frame* frame = &mainFrame();
699 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
700 frame = incrementFrame(frame, true, false);
704 const VisibleSelection& Page::selection() const
706 return focusController().focusedOrMainFrame().selection().selection();
709 void Page::setDefersLoading(bool defers)
711 if (!m_settings->loadDeferringEnabled())
714 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
715 ASSERT(defers || m_defersLoadingCallCount);
716 if (defers && ++m_defersLoadingCallCount > 1)
718 if (!defers && --m_defersLoadingCallCount)
721 ASSERT(!m_defersLoadingCallCount);
722 if (defers == m_defersLoading)
726 m_defersLoading = defers;
727 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
728 frame->loader().setDefersLoading(defers);
731 void Page::clearUndoRedoOperations()
733 m_editorClient.clearUndoRedoOperations();
736 bool Page::inLowQualityImageInterpolationMode() const
738 return m_inLowQualityInterpolationMode;
741 void Page::setInLowQualityImageInterpolationMode(bool mode)
743 m_inLowQualityInterpolationMode = mode;
746 void Page::setMediaVolume(float volume)
748 if (volume < 0 || volume > 1)
751 if (m_mediaVolume == volume)
754 m_mediaVolume = volume;
755 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
756 frame->document()->mediaVolumeDidChange();
760 void Page::setZoomedOutPageScaleFactor(float scale)
762 if (m_zoomedOutPageScaleFactor == scale)
764 m_zoomedOutPageScaleFactor = scale;
766 mainFrame().deviceOrPageScaleFactorChanged();
769 void Page::setPageScaleFactor(float scale, const IntPoint& origin, bool inStableState)
771 Document* document = mainFrame().document();
772 FrameView* view = document->view();
774 if (scale == m_pageScaleFactor) {
775 if (view && view->scrollPosition() != origin) {
776 if (!m_settings->delegatesPageScaling())
777 document->updateLayoutIgnorePendingStylesheets();
779 if (!view->delegatesScrolling())
780 view->setScrollPosition(origin);
781 #if USE(COORDINATED_GRAPHICS)
783 view->requestScrollPositionUpdate(origin);
786 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
788 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
789 frame->document()->pageScaleFactorChangedAndStable();
795 m_pageScaleFactor = scale;
797 if (!m_settings->delegatesPageScaling()) {
798 if (document->renderView())
799 document->renderView()->setNeedsLayout();
801 document->recalcStyle(Style::Force);
803 // Transform change on RenderView doesn't trigger repaint on non-composited contents.
804 mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
807 mainFrame().deviceOrPageScaleFactorChanged();
809 if (view && view->fixedElementsLayoutRelativeToFrame())
810 view->setViewportConstrainedObjectsNeedLayout();
812 if (view && view->scrollPosition() != origin) {
813 if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout())
816 if (!view->delegatesScrolling())
817 view->setScrollPosition(origin);
818 #if USE(COORDINATED_GRAPHICS)
820 view->requestScrollPositionUpdate(origin);
824 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
826 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
827 frame->document()->pageScaleFactorChangedAndStable();
830 UNUSED_PARAM(inStableState);
834 void Page::setViewScaleFactor(float scale)
836 if (m_viewScaleFactor == scale)
839 m_viewScaleFactor = scale;
840 PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
841 PageCache::singleton().markPagesForFullStyleRecalc(*this);
844 void Page::setDeviceScaleFactor(float scaleFactor)
846 ASSERT(scaleFactor > 0);
847 if (scaleFactor <= 0)
850 if (m_deviceScaleFactor == scaleFactor)
853 m_deviceScaleFactor = scaleFactor;
854 setNeedsRecalcStyleInAllFrames();
856 mainFrame().deviceOrPageScaleFactorChanged();
857 PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
859 PageCache::singleton().markPagesForFullStyleRecalc(*this);
860 GraphicsContext::updateDocumentMarkerResources();
862 mainFrame().pageOverlayController().didChangeDeviceScaleFactor();
865 void Page::setTopContentInset(float contentInset)
867 if (m_topContentInset == contentInset)
870 m_topContentInset = contentInset;
872 if (FrameView* view = mainFrame().view())
873 view->topContentInsetDidChange(m_topContentInset);
876 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
878 if (suppressAnimations == m_suppressScrollbarAnimations)
881 lockAllOverlayScrollbarsToHidden(suppressAnimations);
882 m_suppressScrollbarAnimations = suppressAnimations;
885 void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars)
887 FrameView* view = mainFrame().view();
891 view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
893 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
894 FrameView* frameView = frame->view();
898 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
899 if (!scrollableAreas)
902 for (auto& scrollableArea : *scrollableAreas)
903 scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
907 void Page::setVerticalScrollElasticity(ScrollElasticity elasticity)
909 if (m_verticalScrollElasticity == elasticity)
912 m_verticalScrollElasticity = elasticity;
914 if (FrameView* view = mainFrame().view())
915 view->setVerticalScrollElasticity(elasticity);
918 void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity)
920 if (m_horizontalScrollElasticity == elasticity)
923 m_horizontalScrollElasticity = elasticity;
925 if (FrameView* view = mainFrame().view())
926 view->setHorizontalScrollElasticity(elasticity);
929 void Page::setPagination(const Pagination& pagination)
931 if (m_pagination == pagination)
934 m_pagination = pagination;
936 setNeedsRecalcStyleInAllFrames();
937 PageCache::singleton().markPagesForFullStyleRecalc(*this);
940 unsigned Page::pageCount() const
942 if (m_pagination.mode == Pagination::Unpaginated)
945 if (Document* document = mainFrame().document())
946 document->updateLayoutIgnorePendingStylesheets();
948 RenderView* contentRenderer = mainFrame().contentRenderer();
949 return contentRenderer ? contentRenderer->pageCount() : 0;
952 void Page::setIsInWindow(bool isInWindow)
954 setViewState(isInWindow ? m_viewState | ViewState::IsInWindow : m_viewState & ~ViewState::IsInWindow);
957 void Page::setIsInWindowInternal(bool isInWindow)
959 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
960 if (FrameView* frameView = frame->view())
961 frameView->setIsInWindow(isInWindow);
965 resumeAnimatingImages();
968 void Page::addViewStateChangeObserver(ViewStateChangeObserver& observer)
970 m_viewStateChangeObservers.add(&observer);
973 void Page::removeViewStateChangeObserver(ViewStateChangeObserver& observer)
975 m_viewStateChangeObservers.remove(&observer);
978 void Page::suspendScriptedAnimations()
980 m_scriptedAnimationsSuspended = true;
981 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
982 if (frame->document())
983 frame->document()->suspendScriptedAnimationControllerCallbacks();
987 void Page::resumeScriptedAnimations()
989 m_scriptedAnimationsSuspended = false;
990 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
991 if (frame->document())
992 frame->document()->resumeScriptedAnimationControllerCallbacks();
996 void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
998 setTimerThrottlingEnabled(isVisuallyIdle);
1000 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1001 if (frame->document())
1002 frame->document()->scriptedAnimationControllerSetThrottled(isVisuallyIdle);
1006 void Page::userStyleSheetLocationChanged()
1008 // FIXME: Eventually we will move to a model of just being handed the sheet
1009 // text instead of loading the URL ourselves.
1010 URL url = m_settings->userStyleSheetLocation();
1012 // Allow any local file URL scheme to be loaded.
1013 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
1014 m_userStyleSheetPath = url.fileSystemPath();
1016 m_userStyleSheetPath = String();
1018 m_didLoadUserStyleSheet = false;
1019 m_userStyleSheet = String();
1020 m_userStyleSheetModificationTime = 0;
1022 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
1023 // synchronously and avoid using a loader.
1024 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
1025 m_didLoadUserStyleSheet = true;
1027 Vector<char> styleSheetAsUTF8;
1028 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
1029 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
1032 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1033 if (frame->document())
1034 frame->document()->styleSheetCollection().updatePageUserSheet();
1038 const String& Page::userStyleSheet() const
1040 if (m_userStyleSheetPath.isEmpty())
1041 return m_userStyleSheet;
1044 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
1045 // The stylesheet either doesn't exist, was just deleted, or is
1046 // otherwise unreadable. If we've read the stylesheet before, we should
1047 // throw away that data now as it no longer represents what's on disk.
1048 m_userStyleSheet = String();
1049 return m_userStyleSheet;
1052 // If the stylesheet hasn't changed since the last time we read it, we can
1053 // just return the old data.
1054 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
1055 return m_userStyleSheet;
1057 m_didLoadUserStyleSheet = true;
1058 m_userStyleSheet = String();
1059 m_userStyleSheetModificationTime = modTime;
1061 // FIXME: It would be better to load this asynchronously to avoid blocking
1062 // the process, but we will first need to create an asynchronous loading
1063 // mechanism that is not tied to a particular Frame. We will also have to
1064 // determine what our behavior should be before the stylesheet is loaded
1065 // and what should happen when it finishes loading, especially with respect
1066 // to when the load event fires, when Document::close is called, and when
1067 // layout/paint are allowed to happen.
1068 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
1070 return m_userStyleSheet;
1072 m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size());
1074 return m_userStyleSheet;
1077 void Page::invalidateStylesForAllLinks()
1079 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1080 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
1083 void Page::invalidateStylesForLink(LinkHash linkHash)
1085 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1086 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
1089 void Page::setDebugger(JSC::Debugger* debugger)
1091 if (m_debugger == debugger)
1094 m_debugger = debugger;
1096 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1097 frame->script().attachDebugger(m_debugger);
1100 StorageNamespace* Page::sessionStorage(bool optionalCreate)
1102 if (!m_sessionStorage && optionalCreate)
1103 m_sessionStorage = m_storageNamespaceProvider->createSessionStorageNamespace(*this, m_settings->sessionStorageQuota());
1105 return m_sessionStorage.get();
1108 void Page::setSessionStorage(RefPtr<StorageNamespace>&& newStorage)
1110 m_sessionStorage = WTF::move(newStorage);
1113 bool Page::hasCustomHTMLTokenizerTimeDelay() const
1115 return m_settings->maxParseDuration() != -1;
1118 double Page::customHTMLTokenizerTimeDelay() const
1120 ASSERT(m_settings->maxParseDuration() != -1);
1121 return m_settings->maxParseDuration();
1124 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1126 if (m_areMemoryCacheClientCallsEnabled == enabled)
1129 m_areMemoryCacheClientCallsEnabled = enabled;
1133 for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1134 frame->loader().tellClientAboutPastMemoryCacheLoads();
1137 void Page::hiddenPageDOMTimerThrottlingStateChanged()
1139 setTimerThrottlingEnabled(m_viewState & ViewState::IsVisuallyIdle);
1142 void Page::setTimerThrottlingEnabled(bool enabled)
1144 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1145 if (!m_settings->hiddenPageDOMTimerThrottlingEnabled())
1149 if (enabled == m_timerThrottlingEnabled)
1152 m_timerThrottlingEnabled = enabled;
1153 m_settings->setDOMTimerAlignmentInterval(enabled ? DOMTimer::hiddenPageAlignmentInterval() : DOMTimer::defaultAlignmentInterval());
1155 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1156 if (frame->document())
1157 frame->document()->didChangeTimerAlignmentInterval();
1161 void Page::dnsPrefetchingStateChanged()
1163 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1164 frame->document()->initDNSPrefetch();
1167 Vector<Ref<PluginViewBase>> Page::pluginViews()
1169 Vector<Ref<PluginViewBase>> views;
1171 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1172 FrameView* view = frame->view();
1176 for (auto& widget : view->children()) {
1177 if (is<PluginViewBase>(*widget))
1178 views.append(downcast<PluginViewBase>(*widget));
1185 void Page::storageBlockingStateChanged()
1187 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1188 frame->document()->storageBlockingStateDidChange();
1190 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1191 // from below storageBlockingStateChanged does not affect their lifetime.
1192 for (auto& view : pluginViews())
1193 view->storageBlockingStateChanged();
1196 void Page::enableLegacyPrivateBrowsing(bool privateBrowsingEnabled)
1198 // Don't allow changing the legacy private browsing state if we have set a session ID.
1199 ASSERT(m_sessionID == SessionID::defaultSessionID() || m_sessionID == SessionID::legacyPrivateSessionID());
1201 setSessionID(privateBrowsingEnabled ? SessionID::legacyPrivateSessionID() : SessionID::defaultSessionID());
1204 void Page::updateIsPlayingMedia()
1206 MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
1207 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1208 state |= frame->document()->mediaState();
1211 if (state == m_mediaState)
1214 m_mediaState = state;
1216 chrome().client().isPlayingMediaDidChange(state);
1219 void Page::setMuted(bool muted)
1221 if (m_muted == muted)
1226 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1227 frame->document()->pageMutedStateDidChange();
1230 #if !ASSERT_DISABLED
1231 void Page::checkSubframeCountConsistency() const
1233 ASSERT(m_subframeCount >= 0);
1235 int subframeCount = 0;
1236 for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1239 ASSERT(m_subframeCount + 1 == subframeCount);
1243 void Page::resumeAnimatingImages()
1245 // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.)
1246 // require that we repaint animated images to kickstart the animation loop.
1247 if (FrameView* view = mainFrame().view())
1248 view->resumeVisibleImageAnimationsIncludingSubframes();
1251 void Page::setViewState(ViewState::Flags viewState)
1253 ViewState::Flags changed = m_viewState ^ viewState;
1257 ViewState::Flags oldViewState = m_viewState;
1259 m_viewState = viewState;
1260 m_focusController->setViewState(viewState);
1262 if (changed & ViewState::IsVisible)
1263 setIsVisibleInternal(viewState & ViewState::IsVisible);
1264 if (changed & ViewState::IsInWindow)
1265 setIsInWindowInternal(viewState & ViewState::IsInWindow);
1266 if (changed & ViewState::IsVisuallyIdle)
1267 setIsVisuallyIdleInternal(viewState & ViewState::IsVisuallyIdle);
1269 for (auto* observer : m_viewStateChangeObservers)
1270 observer->viewStateDidChange(oldViewState, m_viewState);
1273 void Page::setPageActivityState(PageActivityState::Flags activityState)
1275 chrome().client().setPageActivityState(activityState);
1278 void Page::setIsVisible(bool isVisible)
1281 setViewState((m_viewState & ~ViewState::IsVisuallyIdle) | ViewState::IsVisible | ViewState::IsVisibleOrOccluded);
1283 setViewState((m_viewState & ~(ViewState::IsVisible | ViewState::IsVisibleOrOccluded)) | ViewState::IsVisuallyIdle);
1286 void Page::setIsVisibleInternal(bool isVisible)
1288 // FIXME: The visibility state should be stored on the top-level document.
1289 // https://bugs.webkit.org/show_bug.cgi?id=116769
1292 m_isPrerender = false;
1294 resumeScriptedAnimations();
1296 if (FrameView* view = mainFrame().view())
1299 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1300 mainFrame().animation().resumeAnimations();
1302 resumeAnimatingImages();
1305 Vector<Ref<Document>> documents;
1306 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1307 documents.append(*frame->document());
1309 for (auto& document : documents)
1310 document->visibilityStateChanged();
1313 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1314 mainFrame().animation().suspendAnimations();
1316 suspendScriptedAnimations();
1318 if (FrameView* view = mainFrame().view())
1323 void Page::setIsPrerender()
1325 m_isPrerender = true;
1328 PageVisibilityState Page::visibilityState() const
1331 return PageVisibilityStateVisible;
1333 return PageVisibilityStatePrerender;
1334 return PageVisibilityStateHidden;
1337 #if ENABLE(RUBBER_BANDING)
1338 void Page::addHeaderWithHeight(int headerHeight)
1340 m_headerHeight = headerHeight;
1342 FrameView* frameView = mainFrame().view();
1346 RenderView* renderView = frameView->renderView();
1350 frameView->setHeaderHeight(m_headerHeight);
1351 renderView->compositor().updateLayerForHeader(m_headerHeight);
1354 void Page::addFooterWithHeight(int footerHeight)
1356 m_footerHeight = footerHeight;
1358 FrameView* frameView = mainFrame().view();
1362 RenderView* renderView = frameView->renderView();
1366 frameView->setFooterHeight(m_footerHeight);
1367 renderView->compositor().updateLayerForFooter(m_footerHeight);
1371 #if ENABLE(REMOTE_INSPECTOR)
1372 bool Page::remoteInspectionAllowed() const
1374 return m_inspectorDebuggable->remoteDebuggingAllowed();
1377 void Page::setRemoteInspectionAllowed(bool allowed)
1379 m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed);
1382 void Page::remoteInspectorInformationDidChange() const
1384 m_inspectorDebuggable->update();
1388 void Page::addLayoutMilestones(LayoutMilestones milestones)
1390 // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
1391 m_requestedLayoutMilestones |= milestones;
1394 void Page::removeLayoutMilestones(LayoutMilestones milestones)
1396 m_requestedLayoutMilestones &= ~milestones;
1399 Color Page::pageExtendedBackgroundColor() const
1401 FrameView* frameView = mainFrame().view();
1405 RenderView* renderView = frameView->renderView();
1409 return renderView->compositor().rootExtendedBackgroundColor();
1412 // These are magical constants that might be tweaked over time.
1413 static const double gMinimumPaintedAreaRatio = 0.1;
1414 static const double gMaximumUnpaintedAreaRatio = 0.04;
1416 bool Page::isCountingRelevantRepaintedObjects() const
1418 return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold);
1421 void Page::startCountingRelevantRepaintedObjects()
1423 // Reset everything in case we didn't hit the threshold last time.
1424 resetRelevantPaintedObjectCounter();
1426 m_isCountingRelevantRepaintedObjects = true;
1429 void Page::resetRelevantPaintedObjectCounter()
1431 m_isCountingRelevantRepaintedObjects = false;
1432 m_relevantUnpaintedRenderObjects.clear();
1433 m_topRelevantPaintedRegion = Region();
1434 m_bottomRelevantPaintedRegion = Region();
1435 m_relevantUnpaintedRegion = Region();
1438 static LayoutRect relevantViewRect(RenderView* view)
1440 // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
1441 // a certain relevant amount of content has been drawn to the screen. This is the rect that
1442 // has been determined to be relevant in the context of this goal. We may choose to tweak
1443 // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
1444 // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
1445 LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);
1447 LayoutRect viewRect = view->viewRect();
1448 // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
1449 if (viewRect.width() > relevantViewRect.width())
1450 relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
1452 return relevantViewRect;
1455 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1457 if (!isCountingRelevantRepaintedObjects())
1460 // Objects inside sub-frames are not considered to be relevant.
1461 if (&object->frame() != &mainFrame())
1464 LayoutRect relevantRect = relevantViewRect(&object->view());
1466 // The objects are only relevant if they are being painted within the viewRect().
1467 if (!objectPaintRect.intersects(snappedIntRect(relevantRect)))
1470 IntRect snappedPaintRect = snappedIntRect(objectPaintRect);
1472 // If this object was previously counted as an unpainted object, remove it from that HashSet
1473 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
1474 if (m_relevantUnpaintedRenderObjects.remove(object))
1475 m_relevantUnpaintedRegion.subtract(snappedPaintRect);
1477 // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
1478 // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
1479 // no content beneath that.
1480 LayoutRect topRelevantRect = relevantRect;
1481 topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2));
1482 LayoutRect bottomRelevantRect = topRelevantRect;
1483 bottomRelevantRect.setY(relevantRect.height() / 2);
1485 // If the rect straddles both Regions, split it appropriately.
1486 if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
1487 IntRect topIntersection = snappedPaintRect;
1488 topIntersection.intersect(snappedIntRect(topRelevantRect));
1489 m_topRelevantPaintedRegion.unite(topIntersection);
1491 IntRect bottomIntersection = snappedPaintRect;
1492 bottomIntersection.intersect(snappedIntRect(bottomRelevantRect));
1493 m_bottomRelevantPaintedRegion.unite(bottomIntersection);
1494 } else if (topRelevantRect.intersects(snappedPaintRect))
1495 m_topRelevantPaintedRegion.unite(snappedPaintRect);
1497 m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
1499 float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
1500 float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
1501 float viewArea = relevantRect.width() * relevantRect.height();
1503 float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
1504 float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
1505 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1507 if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
1508 && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1509 m_isCountingRelevantRepaintedObjects = false;
1510 resetRelevantPaintedObjectCounter();
1511 if (Frame* frame = &mainFrame())
1512 frame->loader().didLayout(DidHitRelevantRepaintedObjectsAreaThreshold);
1516 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1518 if (!isCountingRelevantRepaintedObjects())
1521 // The objects are only relevant if they are being painted within the relevantViewRect().
1522 if (!objectPaintRect.intersects(snappedIntRect(relevantViewRect(&object->view()))))
1525 m_relevantUnpaintedRenderObjects.add(object);
1526 m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect));
1529 void Page::suspendActiveDOMObjectsAndAnimations()
1531 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1532 frame->suspendActiveDOMObjectsAndAnimations();
1535 void Page::resumeActiveDOMObjectsAndAnimations()
1537 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1538 frame->resumeActiveDOMObjectsAndAnimations();
1540 resumeAnimatingImages();
1543 bool Page::hasSeenAnyPlugin() const
1545 return !m_seenPlugins.isEmpty();
1548 bool Page::hasSeenPlugin(const String& serviceType) const
1550 return m_seenPlugins.contains(serviceType);
1553 void Page::sawPlugin(const String& serviceType)
1555 m_seenPlugins.add(serviceType);
1558 void Page::resetSeenPlugins()
1560 m_seenPlugins.clear();
1563 bool Page::hasSeenAnyMediaEngine() const
1565 return !m_seenMediaEngines.isEmpty();
1568 bool Page::hasSeenMediaEngine(const String& engineDescription) const
1570 return m_seenMediaEngines.contains(engineDescription);
1573 void Page::sawMediaEngine(const String& engineDescription)
1575 m_seenMediaEngines.add(engineDescription);
1578 void Page::resetSeenMediaEngines()
1580 m_seenMediaEngines.clear();
1583 void Page::hiddenPageCSSAnimationSuspensionStateChanged()
1586 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1587 mainFrame().animation().suspendAnimations();
1589 mainFrame().animation().resumeAnimations();
1593 #if ENABLE(VIDEO_TRACK)
1594 void Page::captionPreferencesChanged()
1596 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1597 frame->document()->captionPreferencesChanged();
1601 void Page::incrementFrameHandlingBeforeUnloadEventCount()
1603 ++m_framesHandlingBeforeUnloadEvent;
1606 void Page::decrementFrameHandlingBeforeUnloadEventCount()
1608 ASSERT(m_framesHandlingBeforeUnloadEvent);
1609 --m_framesHandlingBeforeUnloadEvent;
1612 bool Page::isAnyFrameHandlingBeforeUnloadEvent()
1614 return m_framesHandlingBeforeUnloadEvent;
1617 void Page::setUserContentController(UserContentController* userContentController)
1619 if (m_userContentController)
1620 m_userContentController->removePage(*this);
1622 m_userContentController = userContentController;
1624 if (m_userContentController)
1625 m_userContentController->addPage(*this);
1627 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1628 if (Document *document = frame->document()) {
1629 document->styleSheetCollection().invalidateInjectedStyleSheetCache();
1630 document->styleResolverChanged(DeferRecalcStyle);
1635 void Page::setStorageNamespaceProvider(Ref<StorageNamespaceProvider>&& storageNamespaceProvider)
1637 m_storageNamespaceProvider->removePage(*this);
1638 m_storageNamespaceProvider = WTF::move(storageNamespaceProvider);
1639 m_storageNamespaceProvider->addPage(*this);
1641 // This needs to reset all the local storage namespaces of all the pages.
1644 VisitedLinkStore& Page::visitedLinkStore()
1646 return m_visitedLinkStore;
1649 void Page::setVisitedLinkStore(Ref<VisitedLinkStore>&& visitedLinkStore)
1651 m_visitedLinkStore->removePage(*this);
1652 m_visitedLinkStore = WTF::move(visitedLinkStore);
1653 m_visitedLinkStore->addPage(*this);
1655 invalidateStylesForAllLinks();
1656 PageCache::singleton().markPagesForFullStyleRecalc(*this);
1659 SessionID Page::sessionID() const
1664 void Page::setSessionID(SessionID sessionID)
1666 ASSERT(sessionID.isValid());
1668 bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral());
1670 m_sessionID = sessionID;
1672 if (!privateBrowsingStateChanged)
1675 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1676 frame->document()->privateBrowsingStateDidChange();
1678 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1679 // from below privateBrowsingStateChanged does not affect their lifetime.
1681 for (auto& view : pluginViews())
1682 view->privateBrowsingStateChanged(sessionID.isEphemeral());
1685 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1686 void Page::addPlaybackTargetPickerClient(uint64_t contextId)
1688 chrome().client().addPlaybackTargetPickerClient(contextId);
1691 void Page::removePlaybackTargetPickerClient(uint64_t contextId)
1693 chrome().client().removePlaybackTargetPickerClient(contextId);
1696 void Page::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool isVideo)
1699 // FIXME: refactor iOS implementation.
1700 UNUSED_PARAM(contextId);
1701 UNUSED_PARAM(location);
1702 chrome().client().showPlaybackTargetPicker(isVideo);
1704 chrome().client().showPlaybackTargetPicker(contextId, location, isVideo);
1708 void Page::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
1710 chrome().client().playbackTargetPickerClientStateDidChange(contextId, state);
1713 void Page::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target)
1715 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1716 frame->document()->setPlaybackTarget(contextId, target.copyRef());
1719 void Page::playbackTargetAvailabilityDidChange(uint64_t contextId, bool available)
1721 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1722 frame->document()->playbackTargetAvailabilityDidChange(contextId, available);
1725 void Page::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay)
1727 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1728 frame->document()->setShouldPlayToPlaybackTarget(clientId, shouldPlay);
1732 WheelEventTestTrigger& Page::ensureTestTrigger()
1735 m_testTrigger = adoptRef(new WheelEventTestTrigger());
1737 return *m_testTrigger;
1740 } // namespace WebCore