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