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