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