View scale changes are temporarily lost after restoring a page from the page cache
[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::setViewScaleFactor(float scale)
836 {
837     if (m_viewScaleFactor == scale)
838         return;
839
840     m_viewScaleFactor = scale;
841     PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
842     PageCache::singleton().markPagesForFullStyleRecalc(*this);
843 }
844
845 void Page::setDeviceScaleFactor(float scaleFactor)
846 {
847     ASSERT(scaleFactor > 0);
848     if (scaleFactor <= 0)
849         return;
850     
851     if (m_deviceScaleFactor == scaleFactor)
852         return;
853
854     m_deviceScaleFactor = scaleFactor;
855     setNeedsRecalcStyleInAllFrames();
856
857     mainFrame().deviceOrPageScaleFactorChanged();
858     PageCache::singleton().markPagesForDeviceOrPageScaleChanged(*this);
859
860     PageCache::singleton().markPagesForFullStyleRecalc(*this);
861     GraphicsContext::updateDocumentMarkerResources();
862
863     mainFrame().pageOverlayController().didChangeDeviceScaleFactor();
864 }
865
866 void Page::setTopContentInset(float contentInset)
867 {
868     if (m_topContentInset == contentInset)
869         return;
870     
871     m_topContentInset = contentInset;
872     
873     if (FrameView* view = mainFrame().view())
874         view->topContentInsetDidChange(m_topContentInset);
875 }
876
877 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
878 {
879     if (suppressAnimations == m_suppressScrollbarAnimations)
880         return;
881
882     lockAllOverlayScrollbarsToHidden(suppressAnimations);
883     m_suppressScrollbarAnimations = suppressAnimations;
884 }
885
886 void Page::lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars)
887 {
888     FrameView* view = mainFrame().view();
889     if (!view)
890         return;
891
892     view->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
893     
894     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
895         FrameView* frameView = frame->view();
896         if (!frameView)
897             continue;
898
899         const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
900         if (!scrollableAreas)
901             continue;
902
903         for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
904             ScrollableArea* scrollableArea = *it;
905             scrollableArea->lockOverlayScrollbarStateToHidden(lockOverlayScrollbars);
906         }
907     }
908 }
909     
910 void Page::setVerticalScrollElasticity(ScrollElasticity elasticity)
911 {
912     if (m_verticalScrollElasticity == elasticity)
913         return;
914     
915     m_verticalScrollElasticity = elasticity;
916     
917     if (FrameView* view = mainFrame().view())
918         view->setVerticalScrollElasticity(elasticity);
919 }
920     
921 void Page::setHorizontalScrollElasticity(ScrollElasticity elasticity)
922 {
923     if (m_horizontalScrollElasticity == elasticity)
924         return;
925     
926     m_horizontalScrollElasticity = elasticity;
927     
928     if (FrameView* view = mainFrame().view())
929         view->setHorizontalScrollElasticity(elasticity);
930 }
931
932 void Page::setPagination(const Pagination& pagination)
933 {
934     if (m_pagination == pagination)
935         return;
936
937     m_pagination = pagination;
938
939     setNeedsRecalcStyleInAllFrames();
940     PageCache::singleton().markPagesForFullStyleRecalc(*this);
941 }
942
943 unsigned Page::pageCount() const
944 {
945     if (m_pagination.mode == Pagination::Unpaginated)
946         return 0;
947
948     if (Document* document = mainFrame().document())
949         document->updateLayoutIgnorePendingStylesheets();
950
951     RenderView* contentRenderer = mainFrame().contentRenderer();
952     return contentRenderer ? contentRenderer->pageCount() : 0;
953 }
954
955 void Page::setIsInWindow(bool isInWindow)
956 {
957     setViewState(isInWindow ? m_viewState | ViewState::IsInWindow : m_viewState & ~ViewState::IsInWindow);
958 }
959
960 void Page::setIsInWindowInternal(bool isInWindow)
961 {
962     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
963         if (FrameView* frameView = frame->view())
964             frameView->setIsInWindow(isInWindow);
965     }
966
967     if (isInWindow)
968         resumeAnimatingImages();
969 }
970
971 void Page::addViewStateChangeObserver(ViewStateChangeObserver& observer)
972 {
973     m_viewStateChangeObservers.add(&observer);
974 }
975
976 void Page::removeViewStateChangeObserver(ViewStateChangeObserver& observer)
977 {
978     m_viewStateChangeObservers.remove(&observer);
979 }
980
981 void Page::suspendScriptedAnimations()
982 {
983     m_scriptedAnimationsSuspended = true;
984     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
985         if (frame->document())
986             frame->document()->suspendScriptedAnimationControllerCallbacks();
987     }
988 }
989
990 void Page::resumeScriptedAnimations()
991 {
992     m_scriptedAnimationsSuspended = false;
993     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
994         if (frame->document())
995             frame->document()->resumeScriptedAnimationControllerCallbacks();
996     }
997 }
998
999 void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
1000 {
1001     setTimerThrottlingEnabled(isVisuallyIdle);
1002     
1003     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1004         if (frame->document())
1005             frame->document()->scriptedAnimationControllerSetThrottled(isVisuallyIdle);
1006     }
1007 }
1008
1009 void Page::userStyleSheetLocationChanged()
1010 {
1011     // FIXME: Eventually we will move to a model of just being handed the sheet
1012     // text instead of loading the URL ourselves.
1013     URL url = m_settings->userStyleSheetLocation();
1014     
1015     // Allow any local file URL scheme to be loaded.
1016     if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
1017         m_userStyleSheetPath = url.fileSystemPath();
1018     else
1019         m_userStyleSheetPath = String();
1020
1021     m_didLoadUserStyleSheet = false;
1022     m_userStyleSheet = String();
1023     m_userStyleSheetModificationTime = 0;
1024
1025     // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
1026     // synchronously and avoid using a loader. 
1027     if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
1028         m_didLoadUserStyleSheet = true;
1029
1030         Vector<char> styleSheetAsUTF8;
1031         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
1032             m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
1033     }
1034
1035     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1036         if (frame->document())
1037             frame->document()->styleSheetCollection().updatePageUserSheet();
1038     }
1039 }
1040
1041 const String& Page::userStyleSheet() const
1042 {
1043     if (m_userStyleSheetPath.isEmpty())
1044         return m_userStyleSheet;
1045
1046     time_t modTime;
1047     if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
1048         // The stylesheet either doesn't exist, was just deleted, or is
1049         // otherwise unreadable. If we've read the stylesheet before, we should
1050         // throw away that data now as it no longer represents what's on disk.
1051         m_userStyleSheet = String();
1052         return m_userStyleSheet;
1053     }
1054
1055     // If the stylesheet hasn't changed since the last time we read it, we can
1056     // just return the old data.
1057     if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
1058         return m_userStyleSheet;
1059
1060     m_didLoadUserStyleSheet = true;
1061     m_userStyleSheet = String();
1062     m_userStyleSheetModificationTime = modTime;
1063
1064     // FIXME: It would be better to load this asynchronously to avoid blocking
1065     // the process, but we will first need to create an asynchronous loading
1066     // mechanism that is not tied to a particular Frame. We will also have to
1067     // determine what our behavior should be before the stylesheet is loaded
1068     // and what should happen when it finishes loading, especially with respect
1069     // to when the load event fires, when Document::close is called, and when
1070     // layout/paint are allowed to happen.
1071     RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
1072     if (!data)
1073         return m_userStyleSheet;
1074
1075     m_userStyleSheet = TextResourceDecoder::create("text/css")->decodeAndFlush(data->data(), data->size());
1076
1077     return m_userStyleSheet;
1078 }
1079
1080 void Page::invalidateStylesForAllLinks()
1081 {
1082     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1083         frame->document()->visitedLinkState().invalidateStyleForAllLinks();
1084 }
1085
1086 void Page::invalidateStylesForLink(LinkHash linkHash)
1087 {
1088     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1089         frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
1090 }
1091
1092 void Page::setDebugger(JSC::Debugger* debugger)
1093 {
1094     if (m_debugger == debugger)
1095         return;
1096
1097     m_debugger = debugger;
1098
1099     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1100         frame->script().attachDebugger(m_debugger);
1101 }
1102
1103 StorageNamespace* Page::sessionStorage(bool optionalCreate)
1104 {
1105     if (!m_sessionStorage && optionalCreate)
1106         m_sessionStorage = m_storageNamespaceProvider->createSessionStorageNamespace(*this, m_settings->sessionStorageQuota());
1107
1108     return m_sessionStorage.get();
1109 }
1110
1111 void Page::setSessionStorage(RefPtr<StorageNamespace>&& newStorage)
1112 {
1113     m_sessionStorage = WTF::move(newStorage);
1114 }
1115
1116 bool Page::hasCustomHTMLTokenizerTimeDelay() const
1117 {
1118     return m_settings->maxParseDuration() != -1;
1119 }
1120
1121 double Page::customHTMLTokenizerTimeDelay() const
1122 {
1123     ASSERT(m_settings->maxParseDuration() != -1);
1124     return m_settings->maxParseDuration();
1125 }
1126
1127 void Page::setMemoryCacheClientCallsEnabled(bool enabled)
1128 {
1129     if (m_areMemoryCacheClientCallsEnabled == enabled)
1130         return;
1131
1132     m_areMemoryCacheClientCallsEnabled = enabled;
1133     if (!enabled)
1134         return;
1135
1136     for (RefPtr<Frame> frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1137         frame->loader().tellClientAboutPastMemoryCacheLoads();
1138 }
1139
1140 void Page::hiddenPageDOMTimerThrottlingStateChanged()
1141 {
1142     setTimerThrottlingEnabled(m_viewState & ViewState::IsVisuallyIdle);
1143 }
1144
1145 void Page::setTimerThrottlingEnabled(bool enabled)
1146 {
1147 #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
1148     if (!m_settings->hiddenPageDOMTimerThrottlingEnabled())
1149         enabled = false;
1150 #endif
1151
1152     if (enabled == m_timerThrottlingEnabled)
1153         return;
1154
1155     m_timerThrottlingEnabled = enabled;
1156     m_settings->setDOMTimerAlignmentInterval(enabled ? DOMTimer::hiddenPageAlignmentInterval() : DOMTimer::defaultAlignmentInterval());
1157     
1158     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1159         if (frame->document())
1160             frame->document()->didChangeTimerAlignmentInterval();
1161     }
1162 }
1163
1164 void Page::dnsPrefetchingStateChanged()
1165 {
1166     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1167         frame->document()->initDNSPrefetch();
1168 }
1169
1170 Vector<Ref<PluginViewBase>> Page::pluginViews()
1171 {
1172     Vector<Ref<PluginViewBase>> views;
1173
1174     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1175         FrameView* view = frame->view();
1176         if (!view)
1177             break;
1178
1179         for (auto it = view->children().begin(), end = view->children().end(); it != end; ++it) {
1180             Widget& widget = **it;
1181             if (is<PluginViewBase>(widget))
1182                 views.append(downcast<PluginViewBase>(widget));
1183         }
1184     }
1185
1186     return views;
1187 }
1188
1189 void Page::storageBlockingStateChanged()
1190 {
1191     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1192         frame->document()->storageBlockingStateDidChange();
1193
1194     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1195     // from below storageBlockingStateChanged does not affect their lifetime.
1196     auto views = pluginViews();
1197
1198     for (unsigned i = 0; i < views.size(); ++i)
1199         views[i]->storageBlockingStateChanged();
1200 }
1201
1202 void Page::enableLegacyPrivateBrowsing(bool privateBrowsingEnabled)
1203 {
1204     // Don't allow changing the legacy private browsing state if we have set a session ID.
1205     ASSERT(m_sessionID == SessionID::defaultSessionID() || m_sessionID == SessionID::legacyPrivateSessionID());
1206
1207     setSessionID(privateBrowsingEnabled ? SessionID::legacyPrivateSessionID() : SessionID::defaultSessionID());
1208 }
1209
1210 void Page::updateIsPlayingMedia()
1211 {
1212     MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying;
1213     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1214         state |= frame->document()->mediaState();
1215     }
1216
1217     if (state == m_mediaState)
1218         return;
1219
1220     m_mediaState = state;
1221
1222     chrome().client().isPlayingMediaDidChange(state);
1223 }
1224
1225 void Page::setMuted(bool muted)
1226 {
1227     if (m_muted == muted)
1228         return;
1229
1230     m_muted = muted;
1231
1232     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1233         frame->document()->pageMutedStateDidChange();
1234 }
1235
1236 #if !ASSERT_DISABLED
1237 void Page::checkSubframeCountConsistency() const
1238 {
1239     ASSERT(m_subframeCount >= 0);
1240
1241     int subframeCount = 0;
1242     for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1243         ++subframeCount;
1244
1245     ASSERT(m_subframeCount + 1 == subframeCount);
1246 }
1247 #endif
1248
1249 void Page::resumeAnimatingImages()
1250 {
1251     // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.)
1252     // require that we repaint animated images to kickstart the animation loop.
1253     if (FrameView* view = mainFrame().view())
1254         view->resumeVisibleImageAnimationsIncludingSubframes();
1255 }
1256
1257 void Page::setViewState(ViewState::Flags viewState)
1258 {
1259     ViewState::Flags changed = m_viewState ^ viewState;
1260     if (!changed)
1261         return;
1262
1263     ViewState::Flags oldViewState = m_viewState;
1264
1265     m_viewState = viewState;
1266     m_focusController->setViewState(viewState);
1267
1268     if (changed & ViewState::IsVisible)
1269         setIsVisibleInternal(viewState & ViewState::IsVisible);
1270     if (changed & ViewState::IsInWindow)
1271         setIsInWindowInternal(viewState & ViewState::IsInWindow);
1272     if (changed & ViewState::IsVisuallyIdle)
1273         setIsVisuallyIdleInternal(viewState & ViewState::IsVisuallyIdle);
1274
1275     for (auto* observer : m_viewStateChangeObservers)
1276         observer->viewStateDidChange(oldViewState, m_viewState);
1277 }
1278
1279 void Page::setPageActivityState(PageActivityState::Flags activityState)
1280 {
1281     chrome().client().setPageActivityState(activityState);
1282 }
1283
1284 void Page::setIsVisible(bool isVisible)
1285 {
1286     if (isVisible)
1287         setViewState((m_viewState & ~ViewState::IsVisuallyIdle) | ViewState::IsVisible | ViewState::IsVisibleOrOccluded);
1288     else
1289         setViewState((m_viewState & ~(ViewState::IsVisible | ViewState::IsVisibleOrOccluded)) | ViewState::IsVisuallyIdle);
1290 }
1291
1292 void Page::setIsVisibleInternal(bool isVisible)
1293 {
1294     // FIXME: The visibility state should be stored on the top-level document.
1295     // https://bugs.webkit.org/show_bug.cgi?id=116769
1296
1297     if (isVisible) {
1298         m_isPrerender = false;
1299
1300         resumeScriptedAnimations();
1301
1302         if (FrameView* view = mainFrame().view())
1303             view->show();
1304
1305         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1306             mainFrame().animation().resumeAnimations();
1307
1308         resumeAnimatingImages();
1309     }
1310
1311     Vector<Ref<Document>> documents;
1312     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
1313         documents.append(*frame->document());
1314
1315     for (size_t i = 0, size = documents.size(); i < size; ++i)
1316         documents[i]->visibilityStateChanged();
1317
1318     if (!isVisible) {
1319         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1320             mainFrame().animation().suspendAnimations();
1321
1322         suspendScriptedAnimations();
1323
1324         if (FrameView* view = mainFrame().view())
1325             view->hide();
1326     }
1327 }
1328
1329 void Page::setIsPrerender()
1330 {
1331     m_isPrerender = true;
1332 }
1333
1334 PageVisibilityState Page::visibilityState() const
1335 {
1336     if (isVisible())
1337         return PageVisibilityStateVisible;
1338     if (m_isPrerender)
1339         return PageVisibilityStatePrerender;
1340     return PageVisibilityStateHidden;
1341 }
1342
1343 #if ENABLE(RUBBER_BANDING)
1344 void Page::addHeaderWithHeight(int headerHeight)
1345 {
1346     m_headerHeight = headerHeight;
1347
1348     FrameView* frameView = mainFrame().view();
1349     if (!frameView)
1350         return;
1351
1352     RenderView* renderView = frameView->renderView();
1353     if (!renderView)
1354         return;
1355
1356     frameView->setHeaderHeight(m_headerHeight);
1357     renderView->compositor().updateLayerForHeader(m_headerHeight);
1358 }
1359
1360 void Page::addFooterWithHeight(int footerHeight)
1361 {
1362     m_footerHeight = footerHeight;
1363
1364     FrameView* frameView = mainFrame().view();
1365     if (!frameView)
1366         return;
1367
1368     RenderView* renderView = frameView->renderView();
1369     if (!renderView)
1370         return;
1371
1372     frameView->setFooterHeight(m_footerHeight);
1373     renderView->compositor().updateLayerForFooter(m_footerHeight);
1374 }
1375 #endif
1376
1377 #if ENABLE(REMOTE_INSPECTOR)
1378 bool Page::remoteInspectionAllowed() const
1379 {
1380     return m_inspectorDebuggable->remoteDebuggingAllowed();
1381 }
1382
1383 void Page::setRemoteInspectionAllowed(bool allowed)
1384 {
1385     m_inspectorDebuggable->setRemoteDebuggingAllowed(allowed);
1386 }
1387
1388 void Page::remoteInspectorInformationDidChange() const
1389 {
1390     m_inspectorDebuggable->update();
1391 }
1392 #endif
1393
1394 void Page::addLayoutMilestones(LayoutMilestones milestones)
1395 {
1396     // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
1397     m_requestedLayoutMilestones |= milestones;
1398 }
1399
1400 void Page::removeLayoutMilestones(LayoutMilestones milestones)
1401 {
1402     m_requestedLayoutMilestones &= ~milestones;
1403 }
1404
1405 Color Page::pageExtendedBackgroundColor() const
1406 {
1407     FrameView* frameView = mainFrame().view();
1408     if (!frameView)
1409         return Color();
1410
1411     RenderView* renderView = frameView->renderView();
1412     if (!renderView)
1413         return Color();
1414
1415     return renderView->compositor().rootExtendedBackgroundColor();
1416 }
1417
1418 // These are magical constants that might be tweaked over time.
1419 static double gMinimumPaintedAreaRatio = 0.1;
1420 static double gMaximumUnpaintedAreaRatio = 0.04;
1421
1422 bool Page::isCountingRelevantRepaintedObjects() const
1423 {
1424     return m_isCountingRelevantRepaintedObjects && (m_requestedLayoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold);
1425 }
1426
1427 void Page::startCountingRelevantRepaintedObjects()
1428 {
1429     // Reset everything in case we didn't hit the threshold last time.
1430     resetRelevantPaintedObjectCounter();
1431
1432     m_isCountingRelevantRepaintedObjects = true;
1433 }
1434
1435 void Page::resetRelevantPaintedObjectCounter()
1436 {
1437     m_isCountingRelevantRepaintedObjects = false;
1438     m_relevantUnpaintedRenderObjects.clear();
1439     m_topRelevantPaintedRegion = Region();
1440     m_bottomRelevantPaintedRegion = Region();
1441     m_relevantUnpaintedRegion = Region();
1442 }
1443
1444 static LayoutRect relevantViewRect(RenderView* view)
1445 {
1446     // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
1447     // a certain relevant amount of content has been drawn to the screen. This is the rect that
1448     // has been determined to be relevant in the context of this goal. We may choose to tweak
1449     // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
1450     // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
1451     LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);
1452
1453     LayoutRect viewRect = view->viewRect();
1454     // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
1455     if (viewRect.width() > relevantViewRect.width())
1456         relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
1457
1458     return relevantViewRect;
1459 }
1460
1461 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1462 {
1463     if (!isCountingRelevantRepaintedObjects())
1464         return;
1465
1466     // Objects inside sub-frames are not considered to be relevant.
1467     if (&object->frame() != &mainFrame())
1468         return;
1469
1470     LayoutRect relevantRect = relevantViewRect(&object->view());
1471
1472     // The objects are only relevant if they are being painted within the viewRect().
1473     if (!objectPaintRect.intersects(snappedIntRect(relevantRect)))
1474         return;
1475
1476     IntRect snappedPaintRect = snappedIntRect(objectPaintRect);
1477
1478     // If this object was previously counted as an unpainted object, remove it from that HashSet
1479     // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
1480     if (m_relevantUnpaintedRenderObjects.remove(object))
1481         m_relevantUnpaintedRegion.subtract(snappedPaintRect);
1482
1483     // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
1484     // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
1485     // no content beneath that.
1486     LayoutRect topRelevantRect = relevantRect;
1487     topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2));
1488     LayoutRect bottomRelevantRect = topRelevantRect;
1489     bottomRelevantRect.setY(relevantRect.height() / 2);
1490
1491     // If the rect straddles both Regions, split it appropriately.
1492     if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
1493         IntRect topIntersection = snappedPaintRect;
1494         topIntersection.intersect(snappedIntRect(topRelevantRect));
1495         m_topRelevantPaintedRegion.unite(topIntersection);
1496
1497         IntRect bottomIntersection = snappedPaintRect;
1498         bottomIntersection.intersect(snappedIntRect(bottomRelevantRect));
1499         m_bottomRelevantPaintedRegion.unite(bottomIntersection);
1500     } else if (topRelevantRect.intersects(snappedPaintRect))
1501         m_topRelevantPaintedRegion.unite(snappedPaintRect);
1502     else
1503         m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
1504
1505     float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
1506     float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
1507     float viewArea = relevantRect.width() * relevantRect.height();
1508
1509     float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
1510     float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
1511     float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
1512
1513     if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
1514         && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
1515         m_isCountingRelevantRepaintedObjects = false;
1516         resetRelevantPaintedObjectCounter();
1517         if (Frame* frame = &mainFrame())
1518             frame->loader().didLayout(DidHitRelevantRepaintedObjectsAreaThreshold);
1519     }
1520 }
1521
1522 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
1523 {
1524     if (!isCountingRelevantRepaintedObjects())
1525         return;
1526
1527     // The objects are only relevant if they are being painted within the relevantViewRect().
1528     if (!objectPaintRect.intersects(snappedIntRect(relevantViewRect(&object->view()))))
1529         return;
1530
1531     m_relevantUnpaintedRenderObjects.add(object);
1532     m_relevantUnpaintedRegion.unite(snappedIntRect(objectPaintRect));
1533 }
1534
1535 void Page::suspendActiveDOMObjectsAndAnimations()
1536 {
1537     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1538         frame->suspendActiveDOMObjectsAndAnimations();
1539 }
1540
1541 void Page::resumeActiveDOMObjectsAndAnimations()
1542 {
1543     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1544         frame->resumeActiveDOMObjectsAndAnimations();
1545
1546     resumeAnimatingImages();
1547 }
1548
1549 bool Page::hasSeenAnyPlugin() const
1550 {
1551     return !m_seenPlugins.isEmpty();
1552 }
1553
1554 bool Page::hasSeenPlugin(const String& serviceType) const
1555 {
1556     return m_seenPlugins.contains(serviceType);
1557 }
1558
1559 void Page::sawPlugin(const String& serviceType)
1560 {
1561     m_seenPlugins.add(serviceType);
1562 }
1563
1564 void Page::resetSeenPlugins()
1565 {
1566     m_seenPlugins.clear();
1567 }
1568
1569 bool Page::hasSeenAnyMediaEngine() const
1570 {
1571     return !m_seenMediaEngines.isEmpty();
1572 }
1573
1574 bool Page::hasSeenMediaEngine(const String& engineDescription) const
1575 {
1576     return m_seenMediaEngines.contains(engineDescription);
1577 }
1578
1579 void Page::sawMediaEngine(const String& engineDescription)
1580 {
1581     m_seenMediaEngines.add(engineDescription);
1582 }
1583
1584 void Page::resetSeenMediaEngines()
1585 {
1586     m_seenMediaEngines.clear();
1587 }
1588
1589 void Page::hiddenPageCSSAnimationSuspensionStateChanged()
1590 {
1591     if (!isVisible()) {
1592         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
1593             mainFrame().animation().suspendAnimations();
1594         else
1595             mainFrame().animation().resumeAnimations();
1596     }
1597 }
1598
1599 #if ENABLE(VIDEO_TRACK)
1600 void Page::captionPreferencesChanged()
1601 {
1602     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1603         frame->document()->captionPreferencesChanged();
1604 }
1605 #endif
1606
1607 void Page::incrementFrameHandlingBeforeUnloadEventCount()
1608 {
1609     ++m_framesHandlingBeforeUnloadEvent;
1610 }
1611
1612 void Page::decrementFrameHandlingBeforeUnloadEventCount()
1613 {
1614     ASSERT(m_framesHandlingBeforeUnloadEvent);
1615     --m_framesHandlingBeforeUnloadEvent;
1616 }
1617
1618 bool Page::isAnyFrameHandlingBeforeUnloadEvent()
1619 {
1620     return m_framesHandlingBeforeUnloadEvent;
1621 }
1622
1623 void Page::setUserContentController(UserContentController* userContentController)
1624 {
1625     if (m_userContentController)
1626         m_userContentController->removePage(*this);
1627
1628     m_userContentController = userContentController;
1629
1630     if (m_userContentController)
1631         m_userContentController->addPage(*this);
1632
1633     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
1634         if (Document *document = frame->document()) {
1635             document->styleSheetCollection().invalidateInjectedStyleSheetCache();
1636             document->styleResolverChanged(DeferRecalcStyle);
1637         }
1638     }
1639 }
1640
1641 void Page::setStorageNamespaceProvider(Ref<StorageNamespaceProvider>&& storageNamespaceProvider)
1642 {
1643     m_storageNamespaceProvider->removePage(*this);
1644     m_storageNamespaceProvider = WTF::move(storageNamespaceProvider);
1645     m_storageNamespaceProvider->addPage(*this);
1646
1647     // This needs to reset all the local storage namespaces of all the pages.
1648 }
1649
1650 VisitedLinkStore& Page::visitedLinkStore()
1651 {
1652     return m_visitedLinkStore;
1653 }
1654
1655 void Page::setVisitedLinkStore(Ref<VisitedLinkStore>&& visitedLinkStore)
1656 {
1657     m_visitedLinkStore->removePage(*this);
1658     m_visitedLinkStore = WTF::move(visitedLinkStore);
1659     m_visitedLinkStore->addPage(*this);
1660
1661     invalidateStylesForAllLinks();
1662     PageCache::singleton().markPagesForFullStyleRecalc(*this);
1663 }
1664
1665 SessionID Page::sessionID() const
1666 {
1667     return m_sessionID;
1668 }
1669
1670 void Page::setSessionID(SessionID sessionID)
1671 {
1672     ASSERT(sessionID.isValid());
1673
1674     bool privateBrowsingStateChanged = (sessionID.isEphemeral() != m_sessionID.isEphemeral());
1675
1676     m_sessionID = sessionID;
1677
1678     if (!privateBrowsingStateChanged)
1679         return;
1680
1681     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1682         frame->document()->privateBrowsingStateDidChange();
1683
1684     // Collect the PluginViews in to a vector to ensure that action the plug-in takes
1685     // from below privateBrowsingStateChanged does not affect their lifetime.
1686
1687     for (auto& view : pluginViews())
1688         view->privateBrowsingStateChanged(sessionID.isEphemeral());
1689 }
1690
1691 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1692 void Page::addPlaybackTargetPickerClient(uint64_t contextId)
1693 {
1694     chrome().client().addPlaybackTargetPickerClient(contextId);
1695 }
1696
1697 void Page::removePlaybackTargetPickerClient(uint64_t contextId)
1698 {
1699     chrome().client().removePlaybackTargetPickerClient(contextId);
1700 }
1701
1702 void Page::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool isVideo)
1703 {
1704 #if PLATFORM(IOS)
1705     // FIXME: refactor iOS implementation.
1706     UNUSED_PARAM(contextId);
1707     UNUSED_PARAM(location);
1708     chrome().client().showPlaybackTargetPicker(isVideo);
1709 #else
1710     chrome().client().showPlaybackTargetPicker(contextId, location, isVideo);
1711 #endif
1712 }
1713
1714 void Page::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
1715 {
1716     chrome().client().playbackTargetPickerClientStateDidChange(contextId, state);
1717 }
1718
1719 void Page::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target)
1720 {
1721     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1722         frame->document()->setPlaybackTarget(contextId, target.copyRef());
1723 }
1724
1725 void Page::playbackTargetAvailabilityDidChange(uint64_t contextId, bool available)
1726 {
1727     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1728         frame->document()->playbackTargetAvailabilityDidChange(contextId, available);
1729 }
1730
1731 void Page::setShouldPlayToPlaybackTarget(uint64_t clientId, bool shouldPlay)
1732 {
1733     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
1734         frame->document()->setShouldPlayToPlaybackTarget(clientId, shouldPlay);
1735 }
1736 #endif
1737
1738 WheelEventTestTrigger& Page::ensureTestTrigger()
1739 {
1740     if (!m_testTrigger)
1741         m_testTrigger = adoptRef(new WheelEventTestTrigger());
1742
1743     return *m_testTrigger;
1744 }
1745
1746 } // namespace WebCore