Remove isInitialState flag from Page::setViewState
[WebKit-https.git] / Source / WebCore / page / Page.cpp
1 /*
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/)
4  *
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.
13  *
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.
18  */
19
20 #include "config.h"
21 #include "Page.h"
22
23 #include "AlternativeTextClient.h"
24 #include "AnimationController.h"
25 #include "BackForwardClient.h"
26 #include "BackForwardController.h"
27 #include "Chrome.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"
36 #include "Editor.h"
37 #include "EditorClient.h"
38 #include "Event.h"
39 #include "EventNames.h"
40 #include "ExceptionCode.h"
41 #include "ExceptionCodePlaceholder.h"
42 #include "FileSystem.h"
43 #include "FocusController.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameSelection.h"
47 #include "FrameTree.h"
48 #include "FrameView.h"
49 #include "HTMLElement.h"
50 #include "HistoryController.h"
51 #include "HistoryItem.h"
52 #include "InspectorController.h"
53 #include "InspectorInstrumentation.h"
54 #include "Logging.h"
55 #include "MainFrame.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 "PageDebuggable.h"
63 #include "PageGroup.h"
64 #include "PageThrottler.h"
65 #include "PlugInClient.h"
66 #include "PluginData.h"
67 #include "PluginView.h"
68 #include "PointerLockController.h"
69 #include "ProgressTracker.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"
78 #include "Settings.h"
79 #include "SharedBuffer.h"
80 #include "StorageArea.h"
81 #include "StorageNamespace.h"
82 #include "StyleResolver.h"
83 #include "SubframeLoader.h"
84 #include "TextResourceDecoder.h"
85 #include "UserContentController.h"
86 #include "VisitedLinkState.h"
87 #include "VoidCallback.h"
88 #include "Widget.h"
89 #include <wtf/HashMap.h>
90 #include <wtf/RefCountedLeakCounter.h>
91 #include <wtf/StdLibExtras.h>
92 #include <wtf/text/Base64.h>
93 #include <wtf/text/StringHash.h>
94
95 namespace WebCore {
96
97 static HashSet<Page*>* allPages;
98
99 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
100
101 static void networkStateChanged(bool isOnLine)
102 {
103     Vector<Ref<Frame>> frames;
104     
105     // Get all the frames of all the pages in all the page groups
106     for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) {
107         for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
108             frames.append(*frame);
109         InspectorInstrumentation::networkStateChanged(*it);
110     }
111
112     AtomicString eventName = isOnLine ? eventNames().onlineEvent : eventNames().offlineEvent;
113     for (unsigned i = 0; i < frames.size(); i++)
114         frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
115 }
116
117 float deviceScaleFactor(Frame* frame)
118 {
119     if (!frame)
120         return 1;
121     Page* page = frame->page();
122     if (!page)
123         return 1;
124     return page->deviceScaleFactor();
125 }
126
127 static const ViewState::Flags PageInitialViewState = ViewState::IsVisible | ViewState::IsInWindow;
128
129 Page::Page(PageClients& pageClients)
130     : m_chrome(std::make_unique<Chrome>(*this, *pageClients.chromeClient))
131     , m_dragCaretController(std::make_unique<DragCaretController>())
132 #if ENABLE(DRAG_SUPPORT)
133     , m_dragController(std::make_unique<DragController>(*this, *pageClients.dragClient))
134 #endif
135     , m_focusController(std::make_unique<FocusController>(*this, PageInitialViewState))
136 #if ENABLE(CONTEXT_MENUS)
137     , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageClients.contextMenuClient))
138 #endif
139 #if ENABLE(INSPECTOR)
140     , m_inspectorController(std::make_unique<InspectorController>(*this, pageClients.inspectorClient))
141 #endif
142 #if ENABLE(POINTER_LOCK)
143     , m_pointerLockController(PointerLockController::create(this))
144 #endif
145     , m_settings(Settings::create(this))
146     , m_progress(std::make_unique<ProgressTracker>(*pageClients.progressTrackerClient))
147     , m_backForwardController(std::make_unique<BackForwardController>(*this, pageClients.backForwardClient))
148     , m_mainFrame(MainFrame::create(*this, *pageClients.loaderClientForMainFrame))
149     , m_theme(RenderTheme::themeForPage(this))
150     , m_editorClient(pageClients.editorClient)
151     , m_plugInClient(pageClients.plugInClient)
152     , m_validationMessageClient(pageClients.validationMessageClient)
153     , m_subframeCount(0)
154     , m_openedByDOM(false)
155     , m_tabKeyCyclesThroughElements(true)
156     , m_defersLoading(false)
157     , m_defersLoadingCallCount(0)
158     , m_inLowQualityInterpolationMode(false)
159     , m_areMemoryCacheClientCallsEnabled(true)
160     , m_mediaVolume(1)
161     , m_pageScaleFactor(1)
162     , m_deviceScaleFactor(1)
163     , m_suppressScrollbarAnimations(false)
164     , m_didLoadUserStyleSheet(false)
165     , m_userStyleSheetModificationTime(0)
166     , m_group(0)
167     , m_debugger(0)
168     , m_customHTMLTokenizerTimeDelay(-1)
169     , m_customHTMLTokenizerChunkSize(-1)
170     , m_canStartMedia(true)
171 #if ENABLE(VIEW_MODE_CSS_MEDIA)
172     , m_viewMode(ViewModeWindowed)
173 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
174     , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
175     , m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval())
176     , m_isEditable(false)
177     , m_isPrerender(false)
178     , m_viewState(PageInitialViewState)
179     , m_requestedLayoutMilestones(0)
180     , m_headerHeight(0)
181     , m_footerHeight(0)
182     , m_isCountingRelevantRepaintedObjects(false)
183 #ifndef NDEBUG
184     , m_isPainting(false)
185 #endif
186     , m_alternativeTextClient(pageClients.alternativeTextClient)
187     , m_scriptedAnimationsSuspended(false)
188     , m_pageThrottler(std::make_unique<PageThrottler>(*this))
189     , m_console(std::make_unique<PageConsole>(*this))
190 #if ENABLE(REMOTE_INSPECTOR)
191     , m_inspectorDebuggable(std::make_unique<PageDebuggable>(*this))
192 #endif
193     , m_lastSpatialNavigationCandidatesCount(0) // NOTE: Only called from Internals for Spatial Navigation testing.
194     , m_framesHandlingBeforeUnloadEvent(0)
195 {
196     ASSERT(m_editorClient);
197
198     if (!allPages) {
199         allPages = new HashSet<Page*>;
200         
201         networkStateNotifier().addNetworkStateChangeListener(networkStateChanged);
202     }
203
204     ASSERT(!allPages->contains(this));
205     allPages->add(this);
206
207 #ifndef NDEBUG
208     pageCounter.increment();
209 #endif
210
211 #if ENABLE(REMOTE_INSPECTOR)
212     m_inspectorDebuggable->init();
213 #endif
214 }
215
216 Page::~Page()
217 {
218     m_mainFrame->setView(0);
219     setGroupName(String());
220     allPages->remove(this);
221     
222     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
223         frame->willDetachPage();
224         frame->detachFromPage();
225     }
226
227     m_editorClient->pageDestroyed();
228     if (m_plugInClient)
229         m_plugInClient->pageDestroyed();
230     if (m_alternativeTextClient)
231         m_alternativeTextClient->pageDestroyed();
232
233 #if ENABLE(INSPECTOR)
234     m_inspectorController->inspectedPageDestroyed();
235 #endif
236
237     if (m_scrollingCoordinator)
238         m_scrollingCoordinator->pageDestroyed();
239
240     backForward().close();
241
242 #ifndef NDEBUG
243     pageCounter.decrement();
244 #endif
245
246     if (m_userContentController)
247         m_userContentController->removePage(*this);
248 }
249
250 uint64_t Page::renderTreeSize() const
251 {
252     uint64_t total = 0;
253     for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
254         if (!frame->document() || !frame->document()->renderView())
255             continue;
256         total += frame->document()->renderView()->rendererCount();
257     }
258     return total;
259 }
260
261 ViewportArguments Page::viewportArguments() const
262 {
263     return mainFrame().document() ? mainFrame().document()->viewportArguments() : ViewportArguments();
264 }
265
266 ScrollingCoordinator* Page::scrollingCoordinator()
267 {
268     if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) {
269         m_scrollingCoordinator = chrome().client().createScrollingCoordinator(this);
270         if (!m_scrollingCoordinator)
271             m_scrollingCoordinator = ScrollingCoordinator::create(this);
272     }
273
274     return m_scrollingCoordinator.get();
275 }
276
277 String Page::scrollingStateTreeAsText()
278 {
279     if (Document* document = m_mainFrame->document())
280         document->updateLayout();
281
282     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
283         return scrollingCoordinator->scrollingStateTreeAsText();
284
285     return String();
286 }
287
288 String Page::synchronousScrollingReasonsAsText()
289 {
290     if (Document* document = m_mainFrame->document())
291         document->updateLayout();
292
293     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
294         return scrollingCoordinator->synchronousScrollingReasonsAsText();
295
296     return String();
297 }
298
299 PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
300 {
301     if (Document* document = m_mainFrame->document())
302         document->updateLayout();
303
304     Vector<IntRect> rects;
305     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
306         rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects();
307
308     Vector<FloatQuad> quads(rects.size());
309     for (size_t i = 0; i < rects.size(); ++i)
310         quads[i] = FloatRect(rects[i]);
311     return ClientRectList::create(quads);
312 }
313
314 #if ENABLE(VIEW_MODE_CSS_MEDIA)
315 struct ViewModeInfo {
316     const char* name;
317     Page::ViewMode type;
318 };
319 static const int viewModeMapSize = 5;
320 static ViewModeInfo viewModeMap[viewModeMapSize] = {
321     {"windowed", Page::ViewModeWindowed},
322     {"floating", Page::ViewModeFloating},
323     {"fullscreen", Page::ViewModeFullscreen},
324     {"maximized", Page::ViewModeMaximized},
325     {"minimized", Page::ViewModeMinimized}
326 };
327
328 Page::ViewMode Page::stringToViewMode(const String& text)
329 {
330     for (int i = 0; i < viewModeMapSize; ++i) {
331         if (text == viewModeMap[i].name)
332             return viewModeMap[i].type;
333     }
334     return Page::ViewModeInvalid;
335 }
336
337 void Page::setViewMode(ViewMode viewMode)
338 {
339     if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
340         return;
341
342     m_viewMode = viewMode;
343
344     if (!m_mainFrame)
345         return;
346
347     if (m_mainFrame->view())
348         m_mainFrame->view()->forceLayout();
349
350     if (m_mainFrame->document())
351         m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
352 }
353 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
354
355 bool Page::openedByDOM() const
356 {
357     return m_openedByDOM;
358 }
359
360 void Page::setOpenedByDOM()
361 {
362     m_openedByDOM = true;
363 }
364
365 void Page::goToItem(HistoryItem* item, FrameLoadType type)
366 {
367     // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
368     // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
369     RefPtr<HistoryItem> protector(item);
370
371     if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item))
372         m_mainFrame->loader().stopAllLoaders();
373
374     m_mainFrame->loader().history().goToItem(item, type);
375 }
376
377 void Page::setGroupName(const String& name)
378 {
379     if (m_group && !m_group->name().isEmpty()) {
380         ASSERT(m_group != m_singlePageGroup.get());
381         ASSERT(!m_singlePageGroup);
382         m_group->removePage(*this);
383     }
384
385     if (name.isEmpty())
386         m_group = m_singlePageGroup.get();
387     else {
388         m_singlePageGroup = nullptr;
389         m_group = PageGroup::pageGroup(name);
390         m_group->addPage(*this);
391     }
392 }
393
394 const String& Page::groupName() const
395 {
396     return m_group ? m_group->name() : nullAtom.string();
397 }
398
399 void Page::initGroup()
400 {
401     ASSERT(!m_singlePageGroup);
402     ASSERT(!m_group);
403     m_singlePageGroup = std::make_unique<PageGroup>(*this);
404     m_group = m_singlePageGroup.get();
405 }
406
407 void Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment()
408 {
409     if (!allPages)
410         return;
411     HashSet<Page*>::iterator end = allPages->end();
412     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
413         for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
414             // If a change in the global environment has occurred, we need to
415             // make sure all the properties a recomputed, therefore we invalidate
416             // the properties cache.
417             if (StyleResolver* styleResolver = frame->document()->styleResolverIfExists())
418                 styleResolver->invalidateMatchedPropertiesCache();
419             frame->document()->scheduleForcedStyleRecalc();
420         }
421 }
422
423 void Page::setNeedsRecalcStyleInAllFrames()
424 {
425     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
426         if (Document* document = frame->document())
427             document->styleResolverChanged(DeferRecalcStyle);
428     }
429 }
430
431 void Page::jettisonStyleResolversInAllDocuments()
432 {
433     if (!allPages)
434         return;
435
436     for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) {
437         Page& page = **it;
438         for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
439             if (Document* document = frame->document())
440                 document->clearStyleResolver();
441         }
442     }
443 }
444
445 void Page::refreshPlugins(bool reload)
446 {
447     if (!allPages)
448         return;
449
450     PluginData::refresh();
451
452     Vector<Ref<Frame>> framesNeedingReload;
453
454     for (auto it = allPages->begin(), end = allPages->end(); it != end; ++it) {
455         Page& page = **it;
456         page.m_pluginData.clear();
457
458         if (!reload)
459             continue;
460         
461         for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
462             if (frame->loader().subframeLoader().containsPlugins())
463                 framesNeedingReload.append(*frame);
464         }
465     }
466
467     for (size_t i = 0; i < framesNeedingReload.size(); ++i)
468         framesNeedingReload[i]->loader().reload();
469 }
470
471 PluginData& Page::pluginData() const
472 {
473     if (!m_pluginData)
474         m_pluginData = PluginData::create(this);
475     return *m_pluginData;
476 }
477
478 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
479 {
480     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
481         if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
482             return listener;
483     }
484     return 0;
485 }
486
487 void Page::setCanStartMedia(bool canStartMedia)
488 {
489     if (m_canStartMedia == canStartMedia)
490         return;
491
492     m_canStartMedia = canStartMedia;
493
494     while (m_canStartMedia) {
495         MediaCanStartListener* listener = takeAnyMediaCanStartListener();
496         if (!listener)
497             break;
498         listener->mediaCanStart();
499     }
500 }
501
502 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
503 {
504     return forward
505         ? curr->tree().traverseNextWithWrap(wrapFlag)
506         : curr->tree().traversePreviousWithWrap(wrapFlag);
507 }
508
509 bool Page::findString(const String& target, FindOptions options)
510 {
511     if (target.isEmpty())
512         return false;
513
514     bool shouldWrap = options & WrapAround;
515     Frame* frame = &focusController().focusedOrMainFrame();
516     Frame* startFrame = frame;
517     do {
518         if (frame->editor().findString(target, (options & ~WrapAround) | StartInSelection)) {
519             if (frame != startFrame)
520                 startFrame->selection().clear();
521             focusController().setFocusedFrame(frame);
522             return true;
523         }
524         frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
525     } while (frame && frame != startFrame);
526
527     // Search contents of startFrame, on the other side of the selection that we did earlier.
528     // We cheat a bit and just research with wrap on
529     if (shouldWrap && !startFrame->selection().isNone()) {
530         bool found = startFrame->editor().findString(target, options | WrapAround | StartInSelection);
531         focusController().setFocusedFrame(frame);
532         return found;
533     }
534
535     return false;
536 }
537
538 void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range>>* matchRanges, int& indexForSelection)
539 {
540     indexForSelection = 0;
541
542     Frame* frame = &mainFrame();
543     Frame* frameWithSelection = 0;
544     do {
545         frame->editor().countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges);
546         if (frame->selection().isRange())
547             frameWithSelection = frame;
548         frame = incrementFrame(frame, true, false);
549     } while (frame);
550
551     if (matchRanges->isEmpty())
552         return;
553
554     if (frameWithSelection) {
555         indexForSelection = NoMatchAfterUserSelection;
556         RefPtr<Range> selectedRange = frameWithSelection->selection().selection().firstRange();
557         if (options & Backwards) {
558             for (size_t i = matchRanges->size(); i > 0; --i) {
559                 if (selectedRange->compareBoundaryPoints(Range::END_TO_START, matchRanges->at(i - 1).get(), IGNORE_EXCEPTION) > 0) {
560                     indexForSelection = i - 1;
561                     break;
562                 }
563             }
564         } else {
565             for (size_t i = 0; i < matchRanges->size(); ++i) {
566                 if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), IGNORE_EXCEPTION) < 0) {
567                     indexForSelection = i;
568                     break;
569                 }
570             }
571         }
572     } else {
573         if (options & Backwards)
574             indexForSelection = matchRanges->size() - 1;
575         else
576             indexForSelection = 0;
577     }
578 }
579
580 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
581 {
582     if (target.isEmpty())
583         return 0;
584
585     if (referenceRange && referenceRange->ownerDocument().page() != this)
586         return 0;
587
588     bool shouldWrap = options & WrapAround;
589     Frame* frame = referenceRange ? referenceRange->ownerDocument().frame() : &mainFrame();
590     Frame* startFrame = frame;
591     do {
592         if (RefPtr<Range> resultRange = frame->editor().rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
593             return resultRange.release();
594
595         frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
596     } while (frame && frame != startFrame);
597
598     // Search contents of startFrame, on the other side of the reference range that we did earlier.
599     // We cheat a bit and just search again with wrap on.
600     if (shouldWrap && referenceRange) {
601         if (RefPtr<Range> resultRange = startFrame->editor().rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
602             return resultRange.release();
603     }
604
605     return 0;
606 }
607
608 unsigned Page::findMatchesForText(const String& target, FindOptions options, unsigned maxMatchCount, ShouldHighlightMatches shouldHighlightMatches, ShouldMarkMatches shouldMarkMatches)
609 {
610     if (target.isEmpty())
611         return 0;
612
613     unsigned matchCount = 0;
614
615     Frame* frame = &mainFrame();
616     do {
617         if (shouldMarkMatches == MarkMatches)
618             frame->editor().setMarkedTextMatchesAreHighlighted(shouldHighlightMatches == HighlightMatches);
619         matchCount += frame->editor().countMatchesForText(target, 0, options, maxMatchCount ? (maxMatchCount - matchCount) : 0, shouldMarkMatches == MarkMatches, 0);
620         frame = incrementFrame(frame, true, false);
621     } while (frame);
622
623     return matchCount;
624 }
625
626 unsigned Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned maxMatchCount)
627 {
628     return findMatchesForText(target, options, maxMatchCount, shouldHighlight ? HighlightMatches : DoNotHighlightMatches, MarkMatches);
629 }
630
631 unsigned Page::countFindMatches(const String& target, FindOptions options, unsigned maxMatchCount)
632 {
633     return findMatchesForText(target, options, maxMatchCount, DoNotHighlightMatches, DoNotMarkMatches);
634 }
635
636 void Page::unmarkAllTextMatches()
637 {
638     Frame* frame = &mainFrame();
639     do {
640         frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
641         frame = incrementFrame(frame, true, false);
642     } while (frame);
643 }
644
645 const VisibleSelection& Page::selection() const
646 {
647     return focusController().focusedOrMainFrame().selection().selection();
648 }
649
650 void Page::setDefersLoading(bool defers)
651 {
652     if (!m_settings->loadDeferringEnabled())
653         return;
654
655     if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
656         ASSERT(defers || m_defersLoadingCallCount);
657         if (defers && ++m_defersLoadingCallCount > 1)
658             return;
659         if (!defers && --m_defersLoadingCallCount)
660             return;
661     } else {
662         ASSERT(!m_defersLoadingCallCount);
663         if (defers == m_defersLoading)
664             return;
665     }
666
667     m_defersLoading = defers;
668     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
669         frame->loader().setDefersLoading(defers);
670 }
671
672 void Page::clearUndoRedoOperations()
673 {
674     m_editorClient->clearUndoRedoOperations();
675 }
676
677 bool Page::inLowQualityImageInterpolationMode() const
678 {
679     return m_inLowQualityInterpolationMode;
680 }
681
682 void Page::setInLowQualityImageInterpolationMode(bool mode)
683 {
684     m_inLowQualityInterpolationMode = mode;
685 }
686
687 void Page::setMediaVolume(float volume)
688 {
689     if (volume < 0 || volume > 1)
690         return;
691
692     if (m_mediaVolume == volume)
693         return;
694
695     m_mediaVolume = volume;
696     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
697         frame->document()->mediaVolumeDidChange();
698     }
699 }
700
701 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
702 {
703     Document* document = mainFrame().document();
704     FrameView* view = document->view();
705
706     if (scale == m_pageScaleFactor) {
707         if (view && (view->scrollPosition() != origin || view->delegatesScrolling())) {
708             if (!m_settings->delegatesPageScaling())
709                 document->updateLayoutIgnorePendingStylesheets();
710             view->setScrollPosition(origin);
711         }
712         return;
713     }
714
715     m_pageScaleFactor = scale;
716
717     if (!m_settings->delegatesPageScaling()) {
718         if (document->renderView())
719             document->renderView()->setNeedsLayout();
720
721         document->recalcStyle(Style::Force);
722
723         // Transform change on RenderView doesn't trigger repaint on non-composited contents.
724         mainFrame().view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
725     }
726
727     mainFrame().deviceOrPageScaleFactorChanged();
728
729     if (view && view->fixedElementsLayoutRelativeToFrame())
730         view->setViewportConstrainedObjectsNeedLayout();
731
732     if (view && view->scrollPosition() != origin) {
733         if (!m_settings->delegatesPageScaling() && document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout())
734             view->layout();
735         view->setScrollPosition(origin);
736     }
737 }
738
739
740 void Page::setDeviceScaleFactor(float scaleFactor)
741 {
742     if (m_deviceScaleFactor == scaleFactor)
743         return;
744
745     m_deviceScaleFactor = scaleFactor;
746     setNeedsRecalcStyleInAllFrames();
747
748     mainFrame().deviceOrPageScaleFactorChanged();
749     pageCache()->markPagesForDeviceScaleChanged(this);
750
751     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
752         frame->editor().deviceScaleFactorChanged();
753
754     pageCache()->markPagesForFullStyleRecalc(this);
755     GraphicsContext::updateDocumentMarkerResources();
756 }
757
758 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
759 {
760     if (suppressAnimations == m_suppressScrollbarAnimations)
761         return;
762
763     lockAllOverlayScrollbarsToHidden(suppressAnimations);
764     m_suppressScrollbarAnimations = suppressAnimations;
765 }
766
767 void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars)
768 {
769     FrameView* view = mainFrame().view();
770     if (!view)
771         return;
772
773     view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
774     
775     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
776         FrameView* frameView = frame->view();
777         if (!frameView)
778             continue;
779
780         const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
781         if (!scrollableAreas)
782             continue;
783
784         for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
785             ScrollableArea* scrollableArea = *it;
786             scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
787         }
788     }
789 }
790
791 void Page::setPagination(const Pagination& pagination)
792 {
793     if (m_pagination == pagination)
794         return;
795
796     m_pagination = pagination;
797
798     setNeedsRecalcStyleInAllFrames();
799     pageCache()->markPagesForFullStyleRecalc(this);
800 }
801
802 unsigned Page::pageCount() const
803 {
804     if (m_pagination.mode == Pagination::Unpaginated)
805         return 0;
806
807     if (Document* document = mainFrame().document())
808         document->updateLayoutIgnorePendingStylesheets();
809
810     RenderView* contentRenderer = mainFrame().contentRenderer();
811     return contentRenderer ? contentRenderer->columnCount(contentRenderer->columnInfo()) : 0;
812 }
813
814 void Page::setIsInWindow(bool isInWindow)
815 {
816     setViewState(isInWindow ? m_viewState | ViewState::IsInWindow : m_viewState & ~ViewState::IsInWindow);
817 }
818
819 void Page::setIsInWindowInternal(bool isInWindow)
820 {
821     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
822         if (FrameView* frameView = frame->view())
823             frameView->setIsInWindow(isInWindow);
824     }
825
826     if (isInWindow)
827         resumeAnimatingImages();
828 }
829
830 void Page::suspendScriptedAnimations()
831 {
832     m_scriptedAnimationsSuspended = true;
833     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
834         if (frame->document())
835             frame->document()->suspendScriptedAnimationControllerCallbacks();
836     }
837 }
838
839 void Page::resumeScriptedAnimations()
840 {
841     m_scriptedAnimationsSuspended = false;
842     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
843         if (frame->document())
844             frame->document()->resumeScriptedAnimationControllerCallbacks();
845     }
846 }
847
848 void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
849 {
850     m_pageThrottler->setIsVisuallyIdle(isVisuallyIdle);
851 }
852
853 void Page::userStyleSheetLocationChanged()
854 {
855     // FIXME: Eventually we will move to a model of just being handed the sheet
856     // text instead of loading the URL ourselves.
857     URL url = m_settings->userStyleSheetLocation();
858     
859     // Allow any local file URL scheme to be loaded.
860     if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
861         m_userStyleSheetPath = url.fileSystemPath();
862     else
863         m_userStyleSheetPath = String();
864
865     m_didLoadUserStyleSheet = false;
866     m_userStyleSheet = String();
867     m_userStyleSheetModificationTime = 0;
868
869     // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
870     // synchronously and avoid using a loader. 
871     if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
872         m_didLoadUserStyleSheet = true;
873
874         Vector<char> styleSheetAsUTF8;
875         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
876             m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
877     }
878
879     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
880         if (frame->document())
881             frame->document()->styleSheetCollection().updatePageUserSheet();
882     }
883 }
884
885 const String& Page::userStyleSheet() const
886 {
887     if (m_userStyleSheetPath.isEmpty())
888         return m_userStyleSheet;
889
890     time_t modTime;
891     if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
892         // The stylesheet either doesn't exist, was just deleted, or is
893         // otherwise unreadable. If we've read the stylesheet before, we should
894         // throw away that data now as it no longer represents what's on disk.
895         m_userStyleSheet = String();
896         return m_userStyleSheet;
897     }
898
899     // If the stylesheet hasn't changed since the last time we read it, we can
900     // just return the old data.
901     if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
902         return m_userStyleSheet;
903
904     m_didLoadUserStyleSheet = true;
905     m_userStyleSheet = String();
906     m_userStyleSheetModificationTime = modTime;
907
908     // FIXME: It would be better to load this asynchronously to avoid blocking
909     // the process, but we will first need to create an asynchronous loading
910     // mechanism that is not tied to a particular Frame. We will also have to
911     // determine what our behavior should be before the stylesheet is loaded
912     // and what should happen when it finishes loading, especially with respect
913     // to when the load event fires, when Document::close is called, and when
914     // layout/paint are allowed to happen.
915     RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
916     if (!data)
917         return m_userStyleSheet;
918
919     RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
920     m_userStyleSheet = decoder->decode(data->data(), data->size());
921     m_userStyleSheet.append(decoder->flush());
922
923     return m_userStyleSheet;
924 }
925
926 void Page::removeAllVisitedLinks()
927 {
928     if (!allPages)
929         return;
930     HashSet<PageGroup*> groups;
931     HashSet<Page*>::iterator pagesEnd = allPages->end();
932     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
933         if (PageGroup* group = (*it)->groupPtr())
934             groups.add(group);
935     }
936     HashSet<PageGroup*>::iterator groupsEnd = groups.end();
937     for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
938         (*it)->removeVisitedLinks();
939 }
940
941 void Page::allVisitedStateChanged(PageGroup* group)
942 {
943     ASSERT(group);
944     if (!allPages)
945         return;
946
947     HashSet<Page*>::iterator pagesEnd = allPages->end();
948     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
949         Page* page = *it;
950         if (page->m_group != group)
951             continue;
952         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
953             frame->document()->visitedLinkState().invalidateStyleForAllLinks();
954     }
955 }
956
957 void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash)
958 {
959     ASSERT(group);
960     if (!allPages)
961         return;
962
963     HashSet<Page*>::iterator pagesEnd = allPages->end();
964     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
965         Page* page = *it;
966         if (page->m_group != group)
967             continue;
968         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
969             frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
970     }
971 }
972
973 void Page::setDebugger(JSC::Debugger* debugger)
974 {
975     if (m_debugger == debugger)
976         return;
977
978     m_debugger = debugger;
979
980     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
981         frame->script().attachDebugger(m_debugger);
982 }
983
984 StorageNamespace* Page::sessionStorage(bool optionalCreate)
985 {
986     if (!m_sessionStorage && optionalCreate)
987         m_sessionStorage = StorageNamespace::sessionStorageNamespace(this);
988
989     return m_sessionStorage.get();
990 }
991
992 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
993 {
994     m_sessionStorage = newStorage;
995 }
996
997 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
998 {
999     if (customHTMLTokenizerTimeDelay < 0) {
1000         m_customHTMLTokenizerTimeDelay = -1;
1001         return;
1002     }
1003     m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
1004 }
1005
1006 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
1007 {
1008     if (customHTMLTokenizerChunkSize < 0) {
1009         m_customHTMLTokenizerChunkSize = -1;
1010         return;
1011     }
1012     m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
1013 }
1014
1015 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1016 {
1017     if (m_areMemoryCacheClientCallsEnabled == enabled)
1018         return;
1019
1020     m_areMemoryCacheClientCallsEnabled = enabled;
1021     if (!enabled)
1022         return;
1023
1024     for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1025         frame->loader().tellClientAboutPastMemoryCacheLoads();
1026 }
1027
1028 void Page::setMinimumTimerInterval(double minimumTimerInterval)
1029 {
1030     double oldTimerInterval = m_minimumTimerInterval;
1031     m_minimumTimerInterval = minimumTimerInterval;
1032     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
1033         if (frame->document())
1034             frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
1035     }
1036 }
1037
1038 double Page::minimumTimerInterval() const
1039 {
1040     return m_minimumTimerInterval;
1041 }
1042
1043 void Page::setTimerAlignmentInterval(double interval)
1044 {
1045     if (interval == m_timerAlignmentInterval)
1046         return;
1047
1048     m_timerAlignmentInterval = interval;
1049     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
1050         if (frame->document())
1051             frame->document()->didChangeTimerAlignmentInterval();
1052     }
1053 }
1054
1055 double Page::timerAlignmentInterval() const
1056 {
1057     return m_timerAlignmentInterval;
1058 }
1059
1060 void Page::dnsPrefetchingStateChanged()
1061 {
1062     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1063         frame->document()->initDNSPrefetch();
1064 }
1065
1066 Vector<Ref<PluginViewBase>> Page::pluginViews()
1067 {
1068     Vector<Ref<PluginViewBase>> views;
1069
1070     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1071         FrameView* view = frame->view();
1072         if (!view)
1073             break;
1074
1075         for (auto it = view->children().begin(), end = view->children().end(); it != end; ++it) {
1076             Widget* widget = (*it).get();
1077             if (widget->isPluginViewBase())
1078                 views.append(*toPluginViewBase(widget));
1079         }
1080     }
1081
1082     return views;
1083 }
1084
1085 void Page::storageBlockingStateChanged()
1086 {
1087     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1088         frame->document()->storageBlockingStateDidChange();
1089
1090     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1091     // from below storageBlockingStateChanged does not affect their lifetime.
1092     auto views = pluginViews();
1093
1094     for (unsigned i = 0; i < views.size(); ++i)
1095         views[i]->storageBlockingStateChanged();
1096 }
1097
1098 void Page::privateBrowsingStateChanged()
1099 {
1100     bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
1101
1102     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1103         frame->document()->privateBrowsingStateDidChange();
1104
1105     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1106     // from below privateBrowsingStateChanged does not affect their lifetime.
1107     auto views = pluginViews();
1108
1109     for (unsigned i = 0; i < views.size(); ++i)
1110         views[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
1111 }
1112
1113 #if !ASSERT_DISABLED
1114 void Page::checkSubframeCountConsistency() const
1115 {
1116     ASSERT(m_subframeCount >= 0);
1117
1118     int subframeCount = 0;
1119     for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1120         ++subframeCount;
1121
1122     ASSERT(m_subframeCount + 1 == subframeCount);
1123 }
1124 #endif
1125
1126 void Page::throttleTimers()
1127 {
1128 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1129     if (m_settings->hiddenPageDOMTimerThrottlingEnabled())
1130         setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval());
1131 #endif
1132 }
1133
1134 void Page::unthrottleTimers()
1135 {
1136 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1137     if (m_settings->hiddenPageDOMTimerThrottlingEnabled())
1138         setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval());
1139 #endif
1140 }
1141
1142 void Page::resumeAnimatingImages()
1143 {
1144     // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.)
1145     // require that we repaint animated images to kickstart the animation loop.
1146
1147     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1148         CachedImage::resumeAnimatingImagesForLoader(frame->document()->cachedResourceLoader());
1149 }
1150
1151 void Page::setViewState(ViewState::Flags viewState)
1152 {
1153     ViewState::Flags changed = m_viewState ^ viewState;
1154     if (!changed)
1155         return;
1156
1157     m_viewState = viewState;
1158     m_focusController->setViewState(viewState);
1159
1160     if (changed & ViewState::IsVisible)
1161         setIsVisibleInternal(viewState & ViewState::IsVisible);
1162     if (changed & ViewState::IsInWindow)
1163         setIsInWindowInternal(viewState & ViewState::IsInWindow);
1164     if (changed & ViewState::IsVisuallyIdle)
1165         setIsVisuallyIdleInternal(viewState & ViewState::IsVisuallyIdle);
1166 }
1167
1168 void Page::setIsVisible(bool isVisible)
1169 {
1170     setViewState(isVisible ? m_viewState | ViewState::IsVisible : m_viewState & ~ViewState::IsVisible);
1171 }
1172
1173 void Page::setIsVisibleInternal(bool isVisible)
1174 {
1175     // FIXME: The visibility state should be stored on the top-level document.
1176     // https://bugs.webkit.org/show_bug.cgi?id=116769
1177
1178     if (isVisible) {
1179         m_isPrerender = false;
1180
1181         for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1182             if (FrameView* frameView = frame->view())
1183                 frameView->didMoveOnscreen();
1184         }
1185
1186         resumeScriptedAnimations();
1187
1188         if (FrameView* view = mainFrame().view())
1189             view->show();
1190
1191         unthrottleTimers();
1192
1193 #if ENABLE(PAGE_VISIBILITY_API)
1194         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1195             mainFrame().animation().resumeAnimations();
1196 #endif
1197
1198         resumeAnimatingImages();
1199     }
1200
1201 #if ENABLE(PAGE_VISIBILITY_API)
1202     Vector<Ref<Document>> documents;
1203     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1204         documents.append(*frame->document());
1205
1206     for (size_t i = 0, size = documents.size(); i < size; ++i)
1207         documents[i]->visibilityStateChanged();
1208 #endif
1209
1210     if (!isVisible) {
1211         if (m_pageThrottler->shouldThrottleTimers())
1212             throttleTimers();
1213
1214 #if ENABLE(PAGE_VISIBILITY_API)
1215         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1216             mainFrame().animation().suspendAnimations();
1217 #endif
1218
1219         for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1220             if (FrameView* frameView = frame->view())
1221                 frameView->willMoveOffscreen();
1222         }
1223
1224         suspendScriptedAnimations();
1225
1226         if (FrameView* view = mainFrame().view())
1227             view->hide();
1228     }
1229 }
1230
1231 void Page::setIsPrerender()
1232 {
1233     m_isPrerender = true;
1234 }
1235
1236 #if ENABLE(PAGE_VISIBILITY_API)
1237 PageVisibilityState Page::visibilityState() const
1238 {
1239     if (isVisible())
1240         return PageVisibilityStateVisible;
1241     if (m_isPrerender)
1242         return PageVisibilityStatePrerender;
1243     return PageVisibilityStateHidden;
1244 }
1245 #endif
1246
1247 #if ENABLE(RUBBER_BANDING)
1248 void Page::addHeaderWithHeight(int headerHeight)
1249 {
1250     m_headerHeight = headerHeight;
1251
1252     FrameView* frameView = mainFrame().view();
1253     if (!frameView)
1254         return;
1255
1256     RenderView* renderView = frameView->renderView();
1257     if (!renderView)
1258         return;
1259
1260     frameView->setHeaderHeight(m_headerHeight);
1261     renderView->compositor().updateLayerForHeader(m_headerHeight);
1262 }
1263
1264 void Page::addFooterWithHeight(int footerHeight)
1265 {
1266     m_footerHeight = footerHeight;
1267
1268     FrameView* frameView = mainFrame().view();
1269     if (!frameView)
1270         return;
1271
1272     RenderView* renderView = frameView->renderView();
1273     if (!renderView)
1274         return;
1275
1276     frameView->setFooterHeight(m_footerHeight);
1277     renderView->compositor().updateLayerForFooter(m_footerHeight);
1278 }
1279 #endif
1280
1281 #if ENABLE(REMOTE_INSPECTOR)
1282 bool Page::remoteInspectionAllowed() const
1283 {
1284     return m_inspectorDebuggable->remoteDebuggingAllowed();
1285 }
1286
1287 void Page::setRemoteInspectionAllowed(bool allowed)
1288 {
1289     m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed);
1290 }
1291
1292 void Page::remoteInspectorInformationDidChange() const
1293 {
1294     m_inspectorDebuggable->update();
1295 }
1296 #endif
1297
1298 void Page::addLayoutMilestones(LayoutMilestones milestones)
1299 {
1300     // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
1301     m_requestedLayoutMilestones |= milestones;
1302 }
1303
1304 void Page::removeLayoutMilestones(LayoutMilestones milestones)
1305 {
1306     m_requestedLayoutMilestones &= ~milestones;
1307 }
1308
1309 // These are magical constants that might be tweaked over time.
1310 static double gMinimumPaintedAreaRatio = 0.1;
1311 static double gMaximumUnpaintedAreaRatio = 0.04;
1312
1313 bool Page::isCountingRelevantRepaintedObjects() const
1314 {
1315     return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold);
1316 }
1317
1318 void Page::startCountingRelevantRepaintedObjects()
1319 {
1320     // Reset everything in case we didn't hit the threshold last time.
1321     resetRelevantPaintedObjectCounter();
1322
1323     m_isCountingRelevantRepaintedObjects = true;
1324 }
1325
1326 void Page::resetRelevantPaintedObjectCounter()
1327 {
1328     m_isCountingRelevantRepaintedObjects = false;
1329     m_relevantUnpaintedRenderObjects.clear();
1330     m_topRelevantPaintedRegion = Region();
1331     m_bottomRelevantPaintedRegion = Region();
1332     m_relevantUnpaintedRegion = Region();
1333 }
1334
1335 static LayoutRect relevantViewRect(RenderView* view)
1336 {
1337     // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
1338     // a certain relevant amount of content has been drawn to the screen. This is the rect that
1339     // has been determined to be relevant in the context of this goal. We may choose to tweak
1340     // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
1341     // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
1342     LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);
1343
1344     LayoutRect viewRect = view->viewRect();
1345     // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
1346     if (viewRect.width() > relevantViewRect.width())
1347         relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
1348
1349     return relevantViewRect;
1350 }
1351
1352 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1353 {
1354     if (!isCountingRelevantRepaintedObjects())
1355         return;
1356
1357     // Objects inside sub-frames are not considered to be relevant.
1358     if (&object->frame() != &mainFrame())
1359         return;
1360
1361     LayoutRect relevantRect = relevantViewRect(&object->view());
1362
1363     // The objects are only relevant if they are being painted within the viewRect().
1364     if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantRect)))
1365         return;
1366
1367     IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect);
1368
1369     // If this object was previously counted as an unpainted object, remove it from that HashSet
1370     // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
1371     if (m_relevantUnpaintedRenderObjects.remove(object))
1372         m_relevantUnpaintedRegion.subtract(snappedPaintRect);
1373
1374     // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
1375     // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
1376     // no content beneath that.
1377     LayoutRect topRelevantRect = relevantRect;
1378     topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2));
1379     LayoutRect bottomRelevantRect = topRelevantRect;
1380     bottomRelevantRect.setY(relevantRect.height() / 2);
1381
1382     // If the rect straddles both Regions, split it appropriately.
1383     if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
1384         IntRect topIntersection = snappedPaintRect;
1385         topIntersection.intersect(pixelSnappedIntRect(topRelevantRect));
1386         m_topRelevantPaintedRegion.unite(topIntersection);
1387
1388         IntRect bottomIntersection = snappedPaintRect;
1389         bottomIntersection.intersect(pixelSnappedIntRect(bottomRelevantRect));
1390         m_bottomRelevantPaintedRegion.unite(bottomIntersection);
1391     } else if (topRelevantRect.intersects(snappedPaintRect))
1392         m_topRelevantPaintedRegion.unite(snappedPaintRect);
1393     else
1394         m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
1395
1396     float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
1397     float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
1398     float viewArea = relevantRect.width() * relevantRect.height();
1399
1400     float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
1401     float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
1402     float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1403
1404     if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
1405         && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1406         m_isCountingRelevantRepaintedObjects = false;
1407         resetRelevantPaintedObjectCounter();
1408         if (Frame* frame = &mainFrame())
1409             frame->loader().didLayout(DidHitRelevantRepaintedObjectsAreaThreshold);
1410     }
1411 }
1412
1413 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1414 {
1415     if (!isCountingRelevantRepaintedObjects())
1416         return;
1417
1418     // The objects are only relevant if they are being painted within the relevantViewRect().
1419     if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantViewRect(&object->view()))))
1420         return;
1421
1422     m_relevantUnpaintedRenderObjects.add(object);
1423     m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect));
1424 }
1425
1426 void Page::suspendActiveDOMObjectsAndAnimations()
1427 {
1428     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1429         frame->suspendActiveDOMObjectsAndAnimations();
1430 }
1431
1432 void Page::resumeActiveDOMObjectsAndAnimations()
1433 {
1434     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1435         frame->resumeActiveDOMObjectsAndAnimations();
1436
1437     resumeAnimatingImages();
1438 }
1439
1440 bool Page::hasSeenAnyPlugin() const
1441 {
1442     return !m_seenPlugins.isEmpty();
1443 }
1444
1445 bool Page::hasSeenPlugin(const String& serviceType) const
1446 {
1447     return m_seenPlugins.contains(serviceType);
1448 }
1449
1450 void Page::sawPlugin(const String& serviceType)
1451 {
1452     m_seenPlugins.add(serviceType);
1453 }
1454
1455 void Page::resetSeenPlugins()
1456 {
1457     m_seenPlugins.clear();
1458 }
1459
1460 bool Page::hasSeenAnyMediaEngine() const
1461 {
1462     return !m_seenMediaEngines.isEmpty();
1463 }
1464
1465 bool Page::hasSeenMediaEngine(const String& engineDescription) const
1466 {
1467     return m_seenMediaEngines.contains(engineDescription);
1468 }
1469
1470 void Page::sawMediaEngine(const String& engineDescription)
1471 {
1472     m_seenMediaEngines.add(engineDescription);
1473 }
1474
1475 void Page::resetSeenMediaEngines()
1476 {
1477     m_seenMediaEngines.clear();
1478 }
1479
1480 std::unique_ptr<PageActivityAssertionToken> Page::createActivityToken()
1481 {
1482     return m_pageThrottler->createActivityToken();
1483 }
1484
1485 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1486 void Page::hiddenPageDOMTimerThrottlingStateChanged()
1487 {
1488     if (m_settings->hiddenPageDOMTimerThrottlingEnabled()) {
1489 #if ENABLE(PAGE_VISIBILITY_API)
1490         if (m_pageThrottler->shouldThrottleTimers())
1491             setTimerAlignmentInterval(Settings::hiddenPageDOMTimerAlignmentInterval());
1492 #endif
1493     } else
1494         setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval());
1495 }
1496 #endif
1497
1498 #if (ENABLE_PAGE_VISIBILITY_API)
1499 void Page::hiddenPageCSSAnimationSuspensionStateChanged()
1500 {
1501     if (!isVisible()) {
1502         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1503             mainFrame().animation().suspendAnimations();
1504         else
1505             mainFrame().animation().resumeAnimations();
1506     }
1507 }
1508 #endif
1509
1510 #if ENABLE(VIDEO_TRACK)
1511 void Page::captionPreferencesChanged()
1512 {
1513     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1514         frame->document()->captionPreferencesChanged();
1515 }
1516 #endif
1517
1518 void Page::incrementFrameHandlingBeforeUnloadEventCount()
1519 {
1520     ++m_framesHandlingBeforeUnloadEvent;
1521 }
1522
1523 void Page::decrementFrameHandlingBeforeUnloadEventCount()
1524 {
1525     ASSERT(m_framesHandlingBeforeUnloadEvent);
1526     --m_framesHandlingBeforeUnloadEvent;
1527 }
1528
1529 bool Page::isAnyFrameHandlingBeforeUnloadEvent()
1530 {
1531     return m_framesHandlingBeforeUnloadEvent;
1532 }
1533
1534 void Page::setUserContentController(UserContentController* userContentController)
1535 {
1536     if (m_userContentController)
1537         m_userContentController->removePage(*this);
1538
1539     m_userContentController = userContentController;
1540
1541     if (m_userContentController)
1542         m_userContentController->addPage(*this);
1543 }
1544
1545 Page::PageClients::PageClients()
1546     : alternativeTextClient(nullptr)
1547     , chromeClient(nullptr)
1548 #if ENABLE(CONTEXT_MENUS)
1549     , contextMenuClient(nullptr)
1550 #endif
1551     , editorClient(nullptr)
1552     , dragClient(nullptr)
1553     , inspectorClient(nullptr)
1554     , plugInClient(nullptr)
1555     , progressTrackerClient(nullptr)
1556     , validationMessageClient(nullptr)
1557     , loaderClientForMainFrame(nullptr)
1558 {
1559 }
1560
1561 Page::PageClients::~PageClients()
1562 {
1563 }
1564
1565 } // namespace WebCore