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