2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 "BackForwardController.h"
26 #include "BackForwardList.h"
28 #include "ChromeClient.h"
29 #include "ClientRectList.h"
30 #include "ContextMenuClient.h"
31 #include "ContextMenuController.h"
32 #include "DOMWindow.h"
33 #include "DocumentMarkerController.h"
34 #include "DocumentStyleSheetCollection.h"
35 #include "DragController.h"
37 #include "EditorClient.h"
39 #include "EventNames.h"
40 #include "ExceptionCode.h"
41 #include "ExceptionCodePlaceholder.h"
42 #include "FileSystem.h"
43 #include "FocusController.h"
45 #include "FrameLoader.h"
46 #include "FrameLoaderClient.h"
47 #include "FrameSelection.h"
48 #include "FrameTree.h"
49 #include "FrameView.h"
50 #include "HTMLElement.h"
51 #include "HistoryController.h"
52 #include "HistoryItem.h"
53 #include "InspectorController.h"
54 #include "InspectorInstrumentation.h"
56 #include "MediaCanStartListener.h"
57 #include "Navigator.h"
58 #include "NetworkStateNotifier.h"
59 #include "PageActivityAssertionToken.h"
60 #include "PageCache.h"
61 #include "PageConsole.h"
62 #include "PageGroup.h"
63 #include "PageThrottler.h"
64 #include "PlugInClient.h"
65 #include "PluginData.h"
66 #include "PluginView.h"
67 #include "PointerLockController.h"
68 #include "ProgressTracker.h"
69 #include "RenderArena.h"
70 #include "RenderLayerCompositor.h"
71 #include "RenderTheme.h"
72 #include "RenderView.h"
73 #include "RenderWidget.h"
74 #include "RuntimeEnabledFeatures.h"
75 #include "SchemeRegistry.h"
76 #include "ScriptController.h"
77 #include "ScrollingCoordinator.h"
79 #include "SharedBuffer.h"
80 #include "StorageArea.h"
81 #include "StorageNamespace.h"
82 #include "StyleResolver.h"
83 #include "TextResourceDecoder.h"
84 #include "VisitedLinkState.h"
85 #include "VoidCallback.h"
87 #include <wtf/HashMap.h>
88 #include <wtf/RefCountedLeakCounter.h>
89 #include <wtf/StdLibExtras.h>
90 #include <wtf/text/Base64.h>
91 #include <wtf/text/StringHash.h>
95 static HashSet<Page*>* allPages;
97 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
99 static void networkStateChanged(bool isOnLine)
101 Vector<RefPtr<Frame> > frames;
103 // Get all the frames of all the pages in all the page groups
104 HashSet<Page*>::iterator end = allPages->end();
105 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
106 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
107 frames.append(frame);
108 InspectorInstrumentation::networkStateChanged(*it);
111 AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent;
112 for (unsigned i = 0; i < frames.size(); i++)
113 frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
116 float deviceScaleFactor(Frame* frame)
120 Page* page = frame->page();
123 return page->deviceScaleFactor();
126 Page::Page(PageClients& pageClients)
127 : m_chrome(Chrome::create(this, pageClients.chromeClient))
128 , m_dragCaretController(DragCaretController::create())
129 #if ENABLE(DRAG_SUPPORT)
130 , m_dragController(DragController::create(this, pageClients.dragClient))
132 , m_focusController(FocusController::create(this))
133 #if ENABLE(CONTEXT_MENUS)
134 , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
136 #if ENABLE(INSPECTOR)
137 , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
139 #if ENABLE(POINTER_LOCK)
140 , m_pointerLockController(PointerLockController::create(this))
142 , m_settings(Settings::create(this))
143 , m_progress(ProgressTracker::create())
144 , m_backForwardController(BackForwardController::create(this, pageClients.backForwardClient))
145 , m_mainFrame(Frame::create(this, 0, pageClients.loaderClientForMainFrame))
146 , m_theme(RenderTheme::themeForPage(this))
147 , m_editorClient(pageClients.editorClient)
148 , m_plugInClient(pageClients.plugInClient)
149 , m_validationMessageClient(pageClients.validationMessageClient)
151 , m_openedByDOM(false)
152 , m_tabKeyCyclesThroughElements(true)
153 , m_defersLoading(false)
154 , m_defersLoadingCallCount(0)
155 , m_inLowQualityInterpolationMode(false)
156 , m_cookieEnabled(true)
157 , m_areMemoryCacheClientCallsEnabled(true)
159 , m_pageScaleFactor(1)
160 , m_deviceScaleFactor(1)
161 , m_suppressScrollbarAnimations(false)
162 , m_didLoadUserStyleSheet(false)
163 , m_userStyleSheetModificationTime(0)
166 , m_customHTMLTokenizerTimeDelay(-1)
167 , m_customHTMLTokenizerChunkSize(-1)
168 , m_canStartMedia(true)
169 #if ENABLE(VIEW_MODE_CSS_MEDIA)
170 , m_viewMode(ViewModeWindowed)
171 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
172 , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
173 , m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval())
174 , m_isEditable(false)
177 #if ENABLE(PAGE_VISIBILITY_API)
178 , m_visibilityState(PageVisibilityStateVisible)
180 , m_requestedLayoutMilestones(0)
183 , m_isCountingRelevantRepaintedObjects(false)
185 , m_isPainting(false)
187 , m_alternativeTextClient(pageClients.alternativeTextClient)
188 , m_scriptedAnimationsSuspended(false)
189 , m_pageThrottler(PageThrottler::create(this))
190 , m_console(PageConsole::create(this))
191 , m_lastSpatialNavigationCandidatesCount(0) // NOTE: Only called from Internals for Spatial Navigation testing.
192 , m_framesHandlingBeforeUnloadEvent(0)
194 ASSERT(m_editorClient);
197 allPages = new HashSet<Page*>;
199 networkStateNotifier().addNetworkStateChangeListener(networkStateChanged);
202 ASSERT(!allPages->contains(this));
206 pageCounter.increment();
212 m_mainFrame->setView(0);
213 setGroupName(String());
214 allPages->remove(this);
216 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
217 frame->willDetachPage();
218 frame->detachFromPage();
221 m_editorClient->pageDestroyed();
223 m_plugInClient->pageDestroyed();
224 if (m_alternativeTextClient)
225 m_alternativeTextClient->pageDestroyed();
227 #if ENABLE(INSPECTOR)
228 m_inspectorController->inspectedPageDestroyed();
231 if (m_scrollingCoordinator)
232 m_scrollingCoordinator->pageDestroyed();
234 backForward()->close();
237 pageCounter.decrement();
240 m_pageThrottler.clear();
243 ArenaSize Page::renderTreeSize() const
245 ArenaSize total(0, 0);
246 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
247 if (!frame->document())
249 if (RenderArena* arena = frame->document()->renderArena()) {
250 total.treeSize += arena->totalRenderArenaSize();
251 total.allocated += arena->totalRenderArenaAllocatedBytes();
257 ViewportArguments Page::viewportArguments() const
259 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportArguments() : ViewportArguments();
262 ScrollingCoordinator* Page::scrollingCoordinator()
264 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
265 m_scrollingCoordinator = ScrollingCoordinator::create(this);
267 return m_scrollingCoordinator.get();
270 String Page::scrollingStateTreeAsText()
272 if (Document* document = m_mainFrame->document())
273 document->updateLayout();
275 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
276 return scrollingCoordinator->scrollingStateTreeAsText();
281 String Page::mainThreadScrollingReasonsAsText()
283 if (Document* document = m_mainFrame->document())
284 document->updateLayout();
286 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
287 return scrollingCoordinator->mainThreadScrollingReasonsAsText();
292 PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
294 if (Document* document = m_mainFrame->document())
295 document->updateLayout();
297 Vector<IntRect> rects;
298 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
299 rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects();
301 Vector<FloatQuad> quads(rects.size());
302 for (size_t i = 0; i < rects.size(); ++i)
303 quads[i] = FloatRect(rects[i]);
304 return ClientRectList::create(quads);
307 #if ENABLE(VIEW_MODE_CSS_MEDIA)
308 struct ViewModeInfo {
312 static const int viewModeMapSize = 5;
313 static ViewModeInfo viewModeMap[viewModeMapSize] = {
314 {"windowed", Page::ViewModeWindowed},
315 {"floating", Page::ViewModeFloating},
316 {"fullscreen", Page::ViewModeFullscreen},
317 {"maximized", Page::ViewModeMaximized},
318 {"minimized", Page::ViewModeMinimized}
321 Page::ViewMode Page::stringToViewMode(const String& text)
323 for (int i = 0; i < viewModeMapSize; ++i) {
324 if (text == viewModeMap[i].name)
325 return viewModeMap[i].type;
327 return Page::ViewModeInvalid;
330 void Page::setViewMode(ViewMode viewMode)
332 if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
335 m_viewMode = viewMode;
340 if (m_mainFrame->view())
341 m_mainFrame->view()->forceLayout();
343 if (m_mainFrame->document())
344 m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
346 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
348 bool Page::openedByDOM() const
350 return m_openedByDOM;
353 void Page::setOpenedByDOM()
355 m_openedByDOM = true;
358 BackForwardList* Page::backForwardList() const
360 return m_backForwardController->client();
365 HistoryItem* item = backForward()->backItem();
368 goToItem(item, FrameLoadTypeBack);
374 bool Page::goForward()
376 HistoryItem* item = backForward()->forwardItem();
379 goToItem(item, FrameLoadTypeForward);
385 bool Page::canGoBackOrForward(int distance) const
389 if (distance > 0 && distance <= backForward()->forwardCount())
391 if (distance < 0 && -distance <= backForward()->backCount())
396 void Page::goBackOrForward(int distance)
401 HistoryItem* item = backForward()->itemAtIndex(distance);
404 if (int forwardCount = backForward()->forwardCount())
405 item = backForward()->itemAtIndex(forwardCount);
407 if (int backCount = backForward()->backCount())
408 item = backForward()->itemAtIndex(-backCount);
415 goToItem(item, FrameLoadTypeIndexedBackForward);
418 void Page::goToItem(HistoryItem* item, FrameLoadType type)
420 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
421 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
422 RefPtr<HistoryItem> protector(item);
424 if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item))
425 m_mainFrame->loader().stopAllLoaders();
427 m_mainFrame->loader().history().goToItem(item, type);
430 int Page::getHistoryLength()
432 return backForward()->backCount() + 1 + backForward()->forwardCount();
435 void Page::setGroupName(const String& name)
437 if (m_group && !m_group->name().isEmpty()) {
438 ASSERT(m_group != m_singlePageGroup.get());
439 ASSERT(!m_singlePageGroup);
440 m_group->removePage(this);
444 m_group = m_singlePageGroup.get();
446 m_singlePageGroup.clear();
447 m_group = PageGroup::pageGroup(name);
448 m_group->addPage(this);
452 const String& Page::groupName() const
454 return m_group ? m_group->name() : nullAtom.string();
457 void Page::initGroup()
459 ASSERT(!m_singlePageGroup);
461 m_singlePageGroup = PageGroup::create(this);
462 m_group = m_singlePageGroup.get();
465 void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment()
469 HashSet<Page*>::iterator end = allPages->end();
470 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
471 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
472 // If a change in the global environment has occurred, we need to
473 // make sure all the properties a recomputed, therefore we invalidate
474 // the properties cache.
475 if (StyleResolver* styleResolver = frame->document()->styleResolverIfExists())
476 styleResolver->invalidateMatchedPropertiesCache();
477 frame->document()->scheduleForcedStyleRecalc();
481 void Page::setNeedsRecalcStyleInAllFrames()
483 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
484 if (Document* document = frame->document())
485 document->styleResolverChanged(DeferRecalcStyle);
489 void Page::refreshPlugins(bool reload)
494 PluginData::refresh();
496 Vector<RefPtr<Frame> > framesNeedingReload;
498 HashSet<Page*>::iterator end = allPages->end();
499 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
502 // Clear out the page's plug-in data.
503 if (page->m_pluginData)
504 page->m_pluginData = 0;
509 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
510 if (frame->loader().subframeLoader()->containsPlugins())
511 framesNeedingReload.append(frame);
515 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
516 framesNeedingReload[i]->loader().reload();
519 PluginData* Page::pluginData() const
522 m_pluginData = PluginData::create(this);
523 return m_pluginData.get();
526 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
528 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
529 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
535 void Page::setCanStartMedia(bool canStartMedia)
537 if (m_canStartMedia == canStartMedia)
540 m_canStartMedia = canStartMedia;
542 while (m_canStartMedia) {
543 MediaCanStartListener* listener = takeAnyMediaCanStartListener();
546 listener->mediaCanStart();
550 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
553 ? curr->tree().traverseNextWithWrap(wrapFlag)
554 : curr->tree().traversePreviousWithWrap(wrapFlag);
557 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
559 return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
562 bool Page::findString(const String& target, FindOptions options)
564 if (target.isEmpty() || !mainFrame())
567 bool shouldWrap = options & WrapAround;
568 Frame* frame = focusController().focusedOrMainFrame();
569 Frame* startFrame = frame;
571 if (frame->editor().findString(target, (options & ~WrapAround) | StartInSelection)) {
572 if (frame != startFrame)
573 startFrame->selection().clear();
574 focusController().setFocusedFrame(frame);
577 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
578 } while (frame && frame != startFrame);
580 // Search contents of startFrame, on the other side of the selection that we did earlier.
581 // We cheat a bit and just research with wrap on
582 if (shouldWrap && !startFrame->selection().isNone()) {
583 bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection);
584 focusController().setFocusedFrame(frame);
591 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection)
593 indexForSelection = 0;
597 Frame* frame = mainFrame();
598 Frame* frameWithSelection = 0;
600 frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges);
601 if (frame->selection().isRange())
602 frameWithSelection = frame;
603 frame = incrementFrame(frame, true, false);
606 if (matchRanges->isEmpty())
609 if (frameWithSelection) {
610 indexForSelection = NoMatchAfterUserSelection;
611 RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange();
612 if (options & Backwards) {
613 for (size_t i = matchRanges->size(); i > 0; --i) {
614 if (selectedRange->compareBoundaryPoints(Range::END_TO_START, matchRanges->at(i - 1).get(), IGNORE_EXCEPTION) > 0) {
615 indexForSelection = i - 1;
620 for (size_t i = 0; i < matchRanges->size(); ++i) {
621 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), IGNORE_EXCEPTION) < 0) {
622 indexForSelection = i;
628 if (options & Backwards)
629 indexForSelection = matchRanges->size() - 1;
631 indexForSelection = 0;
635 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
637 if (target.isEmpty() || !mainFrame())
640 if (referenceRange && referenceRange->ownerDocument()->page() != this)
643 bool shouldWrap = options & WrapAround;
644 Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
645 Frame* startFrame = frame;
647 if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
648 return resultRange.release();
650 frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
651 } while (frame && frame != startFrame);
653 // Search contents of startFrame, on the other side of the reference range that we did earlier.
654 // We cheat a bit and just search again with wrap on.
655 if (shouldWrap && referenceRange) {
656 if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
657 return resultRange.release();
663 unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches)
665 if (target.isEmpty() || !mainFrame())
668 unsigned matchCount = 0;
670 Frame* frame = mainFrame();
672 if (shouldMarkMatches == MarkMatches)
673 frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches);
674 matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0);
675 frame = incrementFrame(frame, true, false);
681 unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount)
683 return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches);
686 unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount)
688 return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches);
691 void Page::unmarkAllTextMatches()
696 Frame* frame = mainFrame();
698 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
699 frame = incrementFrame(frame, true, false);
703 const VisibleSelection& Page::selection() const
705 return focusController().focusedOrMainFrame()->selection().selection();
708 void Page::setDefersLoading(bool defers)
710 if (!m_settings->loadDeferringEnabled())
713 if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
714 ASSERT(defers || m_defersLoadingCallCount);
715 if (defers && ++m_defersLoadingCallCount > 1)
717 if (!defers && --m_defersLoadingCallCount)
720 ASSERT(!m_defersLoadingCallCount);
721 if (defers == m_defersLoading)
725 m_defersLoading = defers;
726 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
727 frame->loader().setDefersLoading(defers);
730 void Page::clearUndoRedoOperations()
732 m_editorClient->clearUndoRedoOperations();
735 bool Page::inLowQualityImageInterpolationMode() const
737 return m_inLowQualityInterpolationMode;
740 void Page::setInLowQualityImageInterpolationMode(bool mode)
742 m_inLowQualityInterpolationMode = mode;
745 void Page::setMediaVolume(float volume)
747 if (volume < 0 || volume > 1)
750 if (m_mediaVolume == volume)
753 m_mediaVolume = volume;
754 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
755 frame->document()->mediaVolumeDidChange();
759 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
761 Document* document = mainFrame()->document();
762 FrameView* view = document->view();
764 if (scale == m_pageScaleFactor) {
765 if (view && (view->scrollPosition() != origin || view->delegatesScrolling())) {
766 if (!m_settings->applyPageScaleFactorInCompositor())
767 document->updateLayoutIgnorePendingStylesheets();
768 view->setScrollPosition(origin);
773 m_pageScaleFactor = scale;
775 if (!m_settings->applyPageScaleFactorInCompositor()) {
776 if (document->renderer())
777 document->renderer()->setNeedsLayout(true);
779 document->recalcStyle(Style::Force);
781 // Transform change on RenderView doesn't trigger repaint on non-composited contents.
782 mainFrame()->view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
785 #if USE(ACCELERATED_COMPOSITING)
786 mainFrame()->deviceOrPageScaleFactorChanged();
789 if (view && view->fixedElementsLayoutRelativeToFrame())
790 view->setViewportConstrainedObjectsNeedLayout();
792 if (view && view->scrollPosition() != origin) {
793 if (!m_settings->applyPageScaleFactorInCompositor() && document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
795 view->setScrollPosition(origin);
800 void Page::setDeviceScaleFactor(float scaleFactor)
802 if (m_deviceScaleFactor == scaleFactor)
805 m_deviceScaleFactor = scaleFactor;
806 setNeedsRecalcStyleInAllFrames();
808 #if USE(ACCELERATED_COMPOSITING)
810 mainFrame()->deviceOrPageScaleFactorChanged();
812 pageCache()->markPagesForDeviceScaleChanged(this);
815 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
816 frame->editor().deviceScaleFactorChanged();
818 pageCache()->markPagesForFullStyleRecalc(this);
821 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
823 if (suppressAnimations == m_suppressScrollbarAnimations)
826 if (!suppressAnimations) {
827 // If animations are not going to be suppressed anymore, then there is nothing to do here but
828 // change the cached value.
829 m_suppressScrollbarAnimations = suppressAnimations;
833 // On the other hand, if we are going to start suppressing animations, then we need to make sure we
834 // finish any current scroll animations first.
835 FrameView* view = mainFrame()->view();
839 view->finishCurrentScrollAnimations();
841 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
842 FrameView* frameView = frame->view();
846 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
847 if (!scrollableAreas)
850 for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
851 ScrollableArea* scrollableArea = *it;
852 ASSERT(scrollableArea->scrollbarsCanBeActive());
854 scrollableArea->finishCurrentScrollAnimations();
858 m_suppressScrollbarAnimations = suppressAnimations;
861 bool Page::rubberBandsAtBottom()
863 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
864 return scrollingCoordinator->rubberBandsAtBottom();
869 void Page::setRubberBandsAtBottom(bool rubberBandsAtBottom)
871 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
872 scrollingCoordinator->setRubberBandsAtBottom(rubberBandsAtBottom);
875 bool Page::rubberBandsAtTop()
877 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
878 return scrollingCoordinator->rubberBandsAtTop();
883 void Page::setRubberBandsAtTop(bool rubberBandsAtTop)
885 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
886 scrollingCoordinator->setRubberBandsAtTop(rubberBandsAtTop);
889 void Page::setPagination(const Pagination& pagination)
891 if (m_pagination == pagination)
894 m_pagination = pagination;
896 setNeedsRecalcStyleInAllFrames();
897 pageCache()->markPagesForFullStyleRecalc(this);
900 unsigned Page::pageCount() const
902 if (m_pagination.mode == Pagination::Unpaginated)
905 if (Document* document = mainFrame()->document())
906 document->updateLayoutIgnorePendingStylesheets();
908 RenderView* contentRenderer = mainFrame()->contentRenderer();
909 return contentRenderer ? contentRenderer->columnCount(contentRenderer->columnInfo()) : 0;
912 void Page::didMoveOnscreen()
916 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
917 if (FrameView* frameView = frame->view())
918 frameView->didMoveOnscreen();
921 resumeScriptedAnimations();
924 void Page::willMoveOffscreen()
926 m_isOnscreen = false;
928 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
929 if (FrameView* frameView = frame->view())
930 frameView->willMoveOffscreen();
933 suspendScriptedAnimations();
936 void Page::setIsInWindow(bool isInWindow)
938 if (m_isInWindow == isInWindow)
941 m_isInWindow = isInWindow;
943 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
944 if (FrameView* frameView = frame->view())
945 frameView->setIsInWindow(isInWindow);
949 void Page::suspendScriptedAnimations()
951 m_scriptedAnimationsSuspended = true;
952 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
953 if (frame->document())
954 frame->document()->suspendScriptedAnimationControllerCallbacks();
958 void Page::resumeScriptedAnimations()
960 m_scriptedAnimationsSuspended = false;
961 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
962 if (frame->document())
963 frame->document()->resumeScriptedAnimationControllerCallbacks();
967 void Page::setThrottled(bool throttled)
969 m_pageThrottler->setThrottled(throttled);
972 void Page::userStyleSheetLocationChanged()
974 // FIXME: Eventually we will move to a model of just being handed the sheet
975 // text instead of loading the URL ourselves.
976 KURL url = m_settings->userStyleSheetLocation();
978 // Allow any local file URL scheme to be loaded.
979 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
980 m_userStyleSheetPath = url.fileSystemPath();
982 m_userStyleSheetPath = String();
984 m_didLoadUserStyleSheet = false;
985 m_userStyleSheet = String();
986 m_userStyleSheetModificationTime = 0;
988 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
989 // synchronously and avoid using a loader.
990 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
991 m_didLoadUserStyleSheet = true;
993 Vector<char> styleSheetAsUTF8;
994 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
995 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
998 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
999 if (frame->document())
1000 frame->document()->styleSheetCollection()->updatePageUserSheet();
1004 const String& Page::userStyleSheet() const
1006 if (m_userStyleSheetPath.isEmpty())
1007 return m_userStyleSheet;
1010 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
1011 // The stylesheet either doesn't exist, was just deleted, or is
1012 // otherwise unreadable. If we've read the stylesheet before, we should
1013 // throw away that data now as it no longer represents what's on disk.
1014 m_userStyleSheet = String();
1015 return m_userStyleSheet;
1018 // If the stylesheet hasn't changed since the last time we read it, we can
1019 // just return the old data.
1020 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
1021 return m_userStyleSheet;
1023 m_didLoadUserStyleSheet = true;
1024 m_userStyleSheet = String();
1025 m_userStyleSheetModificationTime = modTime;
1027 // FIXME: It would be better to load this asynchronously to avoid blocking
1028 // the process, but we will first need to create an asynchronous loading
1029 // mechanism that is not tied to a particular Frame. We will also have to
1030 // determine what our behavior should be before the stylesheet is loaded
1031 // and what should happen when it finishes loading, especially with respect
1032 // to when the load event fires, when Document::close is called, and when
1033 // layout/paint are allowed to happen.
1034 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
1036 return m_userStyleSheet;
1038 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
1039 m_userStyleSheet = decoder->decode(data->data(), data->size());
1040 m_userStyleSheet.append(decoder->flush());
1042 return m_userStyleSheet;
1045 void Page::removeAllVisitedLinks()
1049 HashSet<PageGroup*> groups;
1050 HashSet<Page*>::iterator pagesEnd = allPages->end();
1051 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
1052 if (PageGroup* group = (*it)->groupPtr())
1055 HashSet<PageGroup*>::iterator groupsEnd = groups.end();
1056 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
1057 (*it)->removeVisitedLinks();
1060 void Page::allVisitedStateChanged(PageGroup* group)
1066 HashSet<Page*>::iterator pagesEnd = allPages->end();
1067 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
1069 if (page->m_group != group)
1071 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1072 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
1076 void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash)
1082 HashSet<Page*>::iterator pagesEnd = allPages->end();
1083 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
1085 if (page->m_group != group)
1087 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1088 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
1092 void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
1096 HashSet<Page*>::iterator end = allPages->end();
1097 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
1098 (*it)->setDebugger(debugger);
1101 void Page::setDebugger(JSC::Debugger* debugger)
1103 if (m_debugger == debugger)
1106 m_debugger = debugger;
1108 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1109 frame->script().attachDebugger(m_debugger);
1112 StorageNamespace* Page::sessionStorage(bool optionalCreate)
1114 if (!m_sessionStorage && optionalCreate)
1115 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this);
1117 return m_sessionStorage.get();
1120 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
1122 m_sessionStorage = newStorage;
1125 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
1127 if (customHTMLTokenizerTimeDelay < 0) {
1128 m_customHTMLTokenizerTimeDelay = -1;
1131 m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
1134 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
1136 if (customHTMLTokenizerChunkSize < 0) {
1137 m_customHTMLTokenizerChunkSize = -1;
1140 m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
1143 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1145 if (m_areMemoryCacheClientCallsEnabled == enabled)
1148 m_areMemoryCacheClientCallsEnabled = enabled;
1152 for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1153 frame->loader().tellClientAboutPastMemoryCacheLoads();
1156 void Page::setMinimumTimerInterval(double minimumTimerInterval)
1158 double oldTimerInterval = m_minimumTimerInterval;
1159 m_minimumTimerInterval = minimumTimerInterval;
1160 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
1161 if (frame->document())
1162 frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
1166 double Page::minimumTimerInterval() const
1168 return m_minimumTimerInterval;
1171 void Page::setTimerAlignmentInterval(double interval)
1173 if (interval == m_timerAlignmentInterval)
1176 m_timerAlignmentInterval = interval;
1177 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
1178 if (frame->document())
1179 frame->document()->didChangeTimerAlignmentInterval();
1183 double Page::timerAlignmentInterval() const
1185 return m_timerAlignmentInterval;
1188 void Page::dnsPrefetchingStateChanged()
1190 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1191 frame->document()->initDNSPrefetch();
1194 void Page::collectPluginViews(Vector<RefPtr<PluginViewBase>, 32>& pluginViewBases)
1196 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
1197 FrameView* view = frame->view();
1201 const HashSet<RefPtr<Widget> >* children = view->children();
1204 HashSet<RefPtr<Widget> >::const_iterator end = children->end();
1205 for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
1206 Widget* widget = (*it).get();
1207 if (widget->isPluginViewBase())
1208 pluginViewBases.append(toPluginViewBase(widget));
1213 void Page::storageBlockingStateChanged()
1215 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1216 frame->document()->storageBlockingStateDidChange();
1218 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1219 // from below storageBlockingStateChanged does not affect their lifetime.
1220 Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
1221 collectPluginViews(pluginViewBases);
1223 for (size_t i = 0; i < pluginViewBases.size(); ++i)
1224 pluginViewBases[i]->storageBlockingStateChanged();
1227 void Page::privateBrowsingStateChanged()
1229 bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
1231 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1232 frame->document()->privateBrowsingStateDidChange();
1234 // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1235 // from below privateBrowsingStateChanged does not affect their lifetime.
1236 Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
1237 collectPluginViews(pluginViewBases);
1239 for (size_t i = 0; i < pluginViewBases.size(); ++i)
1240 pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
1243 #if !ASSERT_DISABLED
1244 void Page::checkSubframeCountConsistency() const
1246 ASSERT(m_subframeCount >= 0);
1248 int subframeCount = 0;
1249 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1252 ASSERT(m_subframeCount + 1 == subframeCount);
1256 void Page::throttleTimers()
1258 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1259 if (m_settings->hiddenPageDOMTimerThrottlingEnabled())
1260 setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval());
1264 void Page::unthrottleTimers()
1266 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1267 if (m_settings->hiddenPageDOMTimerThrottlingEnabled())
1268 setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval());
1272 #if ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1273 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
1275 #if !ENABLE(PAGE_VISIBILITY_API)
1276 UNUSED_PARAM(isInitialState);
1278 // FIXME: The visibility state should be stored on the top-level document.
1279 // https://bugs.webkit.org/show_bug.cgi?id=116769
1281 if (m_visibilityState == visibilityState)
1283 m_visibilityState = visibilityState;
1285 if (!isInitialState) {
1286 Vector<RefPtr<Document>> documents;
1287 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1288 documents.append(frame->document());
1289 for (size_t i = 0, size = documents.size(); i < size; ++i)
1290 documents[i]->dispatchEvent(Event::create(eventNames().visibilitychangeEvent, false, false));
1294 if (visibilityState == WebCore::PageVisibilityStateHidden) {
1295 if (m_pageThrottler->shouldThrottleTimers())
1297 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1298 mainFrame()->animation().suspendAnimations();
1301 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1302 mainFrame()->animation().resumeAnimations();
1305 #endif // ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1307 #if ENABLE(PAGE_VISIBILITY_API)
1308 PageVisibilityState Page::visibilityState() const
1310 return m_visibilityState;
1314 #if ENABLE(RUBBER_BANDING)
1315 void Page::addHeaderWithHeight(int headerHeight)
1317 m_headerHeight = headerHeight;
1319 FrameView* frameView = mainFrame() ? mainFrame()->view() : 0;
1323 RenderView* renderView = frameView->renderView();
1327 frameView->setHeaderHeight(m_headerHeight);
1328 renderView->compositor().updateLayerForHeader(m_headerHeight);
1331 void Page::addFooterWithHeight(int footerHeight)
1333 m_footerHeight = footerHeight;
1335 FrameView* frameView = mainFrame() ? mainFrame()->view() : 0;
1339 RenderView* renderView = frameView->renderView();
1343 frameView->setFooterHeight(m_footerHeight);
1344 renderView->compositor().updateLayerForFooter(m_footerHeight);
1348 void Page::addLayoutMilestones(LayoutMilestones milestones)
1350 // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
1351 m_requestedLayoutMilestones |= milestones;
1354 void Page::removeLayoutMilestones(LayoutMilestones milestones)
1356 m_requestedLayoutMilestones &= ~milestones;
1359 // These are magical constants that might be tweaked over time.
1360 static double gMinimumPaintedAreaRatio = 0.1;
1361 static double gMaximumUnpaintedAreaRatio = 0.04;
1363 bool Page::isCountingRelevantRepaintedObjects() const
1365 return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold);
1368 void Page::startCountingRelevantRepaintedObjects()
1370 // Reset everything in case we didn't hit the threshold last time.
1371 resetRelevantPaintedObjectCounter();
1373 m_isCountingRelevantRepaintedObjects = true;
1376 void Page::resetRelevantPaintedObjectCounter()
1378 m_isCountingRelevantRepaintedObjects = false;
1379 m_relevantUnpaintedRenderObjects.clear();
1380 m_topRelevantPaintedRegion = Region();
1381 m_bottomRelevantPaintedRegion = Region();
1382 m_relevantUnpaintedRegion = Region();
1385 static LayoutRect relevantViewRect(RenderView* view)
1387 // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
1388 // a certain relevant amount of content has been drawn to the screen. This is the rect that
1389 // has been determined to be relevant in the context of this goal. We may choose to tweak
1390 // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
1391 // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
1392 LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);
1394 LayoutRect viewRect = view->viewRect();
1395 // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
1396 if (viewRect.width() > relevantViewRect.width())
1397 relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
1399 return relevantViewRect;
1402 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1404 if (!isCountingRelevantRepaintedObjects())
1407 // Objects inside sub-frames are not considered to be relevant.
1408 if (&object->frame() != mainFrame())
1411 LayoutRect relevantRect = relevantViewRect(&object->view());
1413 // The objects are only relevant if they are being painted within the viewRect().
1414 if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantRect)))
1417 IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect);
1419 // If this object was previously counted as an unpainted object, remove it from that HashSet
1420 // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
1421 HashSet<RenderObject*>::iterator it = m_relevantUnpaintedRenderObjects.find(object);
1422 if (it != m_relevantUnpaintedRenderObjects.end()) {
1423 m_relevantUnpaintedRenderObjects.remove(it);
1424 m_relevantUnpaintedRegion.subtract(snappedPaintRect);
1427 // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
1428 // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
1429 // no content beneath that.
1430 LayoutRect topRelevantRect = relevantRect;
1431 topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2));
1432 LayoutRect bottomRelevantRect = topRelevantRect;
1433 bottomRelevantRect.setY(relevantRect.height() / 2);
1435 // If the rect straddles both Regions, split it appropriately.
1436 if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
1437 IntRect topIntersection = snappedPaintRect;
1438 topIntersection.intersect(pixelSnappedIntRect(topRelevantRect));
1439 m_topRelevantPaintedRegion.unite(topIntersection);
1441 IntRect bottomIntersection = snappedPaintRect;
1442 bottomIntersection.intersect(pixelSnappedIntRect(bottomRelevantRect));
1443 m_bottomRelevantPaintedRegion.unite(bottomIntersection);
1444 } else if (topRelevantRect.intersects(snappedPaintRect))
1445 m_topRelevantPaintedRegion.unite(snappedPaintRect);
1447 m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
1449 float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
1450 float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
1451 float viewArea = relevantRect.width() * relevantRect.height();
1453 float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
1454 float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
1455 float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1457 if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
1458 && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1459 m_isCountingRelevantRepaintedObjects = false;
1460 resetRelevantPaintedObjectCounter();
1461 if (Frame* frame = mainFrame())
1462 frame->loader().didLayout(DidHitRelevantRepaintedObjectsAreaThreshold);
1466 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1468 if (!isCountingRelevantRepaintedObjects())
1471 // The objects are only relevant if they are being painted within the relevantViewRect().
1472 if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantViewRect(&object->view()))))
1475 m_relevantUnpaintedRenderObjects.add(object);
1476 m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect));
1479 void Page::suspendActiveDOMObjectsAndAnimations()
1481 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1482 frame->suspendActiveDOMObjectsAndAnimations();
1485 void Page::resumeActiveDOMObjectsAndAnimations()
1487 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1488 frame->resumeActiveDOMObjectsAndAnimations();
1491 bool Page::hasSeenAnyPlugin() const
1493 return !m_seenPlugins.isEmpty();
1496 bool Page::hasSeenPlugin(const String& serviceType) const
1498 return m_seenPlugins.contains(serviceType);
1501 void Page::sawPlugin(const String& serviceType)
1503 m_seenPlugins.add(serviceType);
1506 void Page::resetSeenPlugins()
1508 m_seenPlugins.clear();
1511 bool Page::hasSeenAnyMediaEngine() const
1513 return !m_seenMediaEngines.isEmpty();
1516 bool Page::hasSeenMediaEngine(const String& engineDescription) const
1518 return m_seenMediaEngines.contains(engineDescription);
1521 void Page::sawMediaEngine(const String& engineDescription)
1523 m_seenMediaEngines.add(engineDescription);
1526 void Page::resetSeenMediaEngines()
1528 m_seenMediaEngines.clear();
1531 PassOwnPtr<PageActivityAssertionToken> Page::createActivityToken()
1533 return adoptPtr(new PageActivityAssertionToken(m_pageThrottler.get()));
1536 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1537 void Page::hiddenPageDOMTimerThrottlingStateChanged()
1539 if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) {
1540 #if ENABLE(PAGE_VISIBILITY_API)
1541 if (m_pageThrottler->shouldThrottleTimers())
1542 setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval());
1545 setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval());
1549 #if (ENABLE_PAGE_VISIBILITY_API)
1550 void Page::hiddenPageCSSAnimationSuspensionStateChanged()
1552 if (m_visibilityState == WebCore::PageVisibilityStateHidden) {
1553 if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1554 mainFrame()->animation().suspendAnimations();
1556 mainFrame()->animation().resumeAnimations();
1561 #if ENABLE(VIDEO_TRACK)
1562 void Page::captionPreferencesChanged()
1564 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
1565 frame->document()->captionPreferencesChanged();
1569 void Page::incrementFrameHandlingBeforeUnloadEventCount()
1571 ++m_framesHandlingBeforeUnloadEvent;
1574 void Page::decrementFrameHandlingBeforeUnloadEventCount()
1576 ASSERT(m_framesHandlingBeforeUnloadEvent);
1577 --m_framesHandlingBeforeUnloadEvent;
1580 bool Page::isAnyFrameHandlingBeforeUnloadEvent()
1582 return m_framesHandlingBeforeUnloadEvent;
1585 Page::PageClients::PageClients()
1586 : alternativeTextClient(0)
1588 #if ENABLE(CONTEXT_MENUS)
1589 , contextMenuClient(0)
1593 , inspectorClient(0)
1595 , validationMessageClient(0)
1596 , loaderClientForMainFrame(0)
1600 Page::PageClients::~PageClients()
1604 } // namespace WebCore