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