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