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