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