Home | History | Annotate | Download | only in page
      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 "core/page/Page.h"
     22 
     23 #include "core/dom/ClientRectList.h"
     24 #include "core/dom/DocumentMarkerController.h"
     25 #include "core/dom/DocumentStyleSheetCollection.h"
     26 #include "core/dom/Event.h"
     27 #include "core/dom/EventNames.h"
     28 #include "core/dom/VisitedLinkState.h"
     29 #include "core/editing/Caret.h"
     30 #include "core/history/BackForwardController.h"
     31 #include "core/history/HistoryItem.h"
     32 #include "core/inspector/InspectorController.h"
     33 #include "core/inspector/InspectorInstrumentation.h"
     34 #include "core/loader/FrameLoader.h"
     35 #include "core/loader/ProgressTracker.h"
     36 #include "core/page/AutoscrollController.h"
     37 #include "core/page/Chrome.h"
     38 #include "core/page/ContextMenuController.h"
     39 #include "core/page/DOMTimer.h"
     40 #include "core/page/DragController.h"
     41 #include "core/page/FocusController.h"
     42 #include "core/page/Frame.h"
     43 #include "core/page/FrameTree.h"
     44 #include "core/page/FrameView.h"
     45 #include "core/page/PageConsole.h"
     46 #include "core/page/PageGroup.h"
     47 #include "core/page/PageLifecycleNotifier.h"
     48 #include "core/page/PointerLockController.h"
     49 #include "core/page/Settings.h"
     50 #include "core/page/scrolling/ScrollingCoordinator.h"
     51 #include "core/platform/network/NetworkStateNotifier.h"
     52 #include "core/plugins/PluginData.h"
     53 #include "core/rendering/RenderTheme.h"
     54 #include "core/rendering/RenderView.h"
     55 #include "core/storage/StorageNamespace.h"
     56 #include "wtf/HashMap.h"
     57 #include "wtf/RefCountedLeakCounter.h"
     58 #include "wtf/StdLibExtras.h"
     59 #include "wtf/text/Base64.h"
     60 
     61 namespace WebCore {
     62 
     63 static HashSet<Page*>* allPages;
     64 
     65 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
     66 
     67 static void networkStateChanged()
     68 {
     69     Vector<RefPtr<Frame> > frames;
     70 
     71     // Get all the frames of all the pages in all the page groups
     72     HashSet<Page*>::iterator end = allPages->end();
     73     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
     74         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
     75             frames.append(frame);
     76         InspectorInstrumentation::networkStateChanged(*it);
     77     }
     78 
     79     AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
     80     for (unsigned i = 0; i < frames.size(); i++)
     81         frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
     82 }
     83 
     84 float deviceScaleFactor(Frame* frame)
     85 {
     86     if (!frame)
     87         return 1;
     88     Page* page = frame->page();
     89     if (!page)
     90         return 1;
     91     return page->deviceScaleFactor();
     92 }
     93 
     94 Page::Page(PageClients& pageClients)
     95     : m_autoscrollController(AutoscrollController::create())
     96     , m_chrome(Chrome::create(this, pageClients.chromeClient))
     97     , m_dragCaretController(DragCaretController::create())
     98     , m_dragController(DragController::create(this, pageClients.dragClient))
     99     , m_focusController(FocusController::create(this))
    100     , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
    101     , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
    102     , m_pointerLockController(PointerLockController::create(this))
    103     , m_settings(Settings::create(this))
    104     , m_progress(ProgressTracker::create())
    105     , m_backForwardController(BackForwardController::create(this, pageClients.backForwardClient))
    106     , m_theme(RenderTheme::themeForPage(this))
    107     , m_editorClient(pageClients.editorClient)
    108     , m_validationMessageClient(0)
    109     , m_subframeCount(0)
    110     , m_openedByDOM(false)
    111     , m_tabKeyCyclesThroughElements(true)
    112     , m_defersLoading(false)
    113     , m_pageScaleFactor(1)
    114     , m_deviceScaleFactor(1)
    115     , m_didLoadUserStyleSheet(false)
    116     , m_group(0)
    117     , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
    118     , m_visibilityState(PageVisibilityStateVisible)
    119     , m_isCursorVisible(true)
    120     , m_layoutMilestones(0)
    121     , m_isCountingRelevantRepaintedObjects(false)
    122 #ifndef NDEBUG
    123     , m_isPainting(false)
    124 #endif
    125     , m_console(PageConsole::create(this))
    126 {
    127     ASSERT(m_editorClient);
    128 
    129     if (!allPages) {
    130         allPages = new HashSet<Page*>;
    131 
    132         networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
    133     }
    134 
    135     ASSERT(!allPages->contains(this));
    136     allPages->add(this);
    137 
    138 #ifndef NDEBUG
    139     pageCounter.increment();
    140 #endif
    141 }
    142 
    143 Page::~Page()
    144 {
    145     m_mainFrame->setView(0);
    146     clearPageGroup();
    147     allPages->remove(this);
    148 
    149     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
    150         frame->willDetachPage();
    151         frame->detachFromPage();
    152     }
    153 
    154     m_inspectorController->inspectedPageDestroyed();
    155 
    156     if (m_scrollingCoordinator)
    157         m_scrollingCoordinator->pageDestroyed();
    158 
    159     backForward()->close();
    160 
    161 #ifndef NDEBUG
    162     pageCounter.decrement();
    163 #endif
    164 }
    165 
    166 ViewportArguments Page::viewportArguments() const
    167 {
    168     return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportArguments() : ViewportArguments();
    169 }
    170 
    171 bool Page::autoscrollInProgress() const
    172 {
    173     return m_autoscrollController->autoscrollInProgress();
    174 }
    175 
    176 bool Page::autoscrollInProgress(const RenderBox* renderer) const
    177 {
    178     return m_autoscrollController->autoscrollInProgress(renderer);
    179 }
    180 
    181 bool Page::panScrollInProgress() const
    182 {
    183     return m_autoscrollController->panScrollInProgress();
    184 }
    185 
    186 void Page::startAutoscrollForSelection(RenderObject* renderer)
    187 {
    188     return m_autoscrollController->startAutoscrollForSelection(renderer);
    189 }
    190 
    191 void Page::stopAutoscrollIfNeeded(RenderObject* renderer)
    192 {
    193     m_autoscrollController->stopAutoscrollIfNeeded(renderer);
    194 }
    195 
    196 
    197 void Page::stopAutoscrollTimer()
    198 {
    199     m_autoscrollController->stopAutoscrollTimer();
    200 }
    201 
    202 void Page::updateAutoscrollRenderer()
    203 {
    204     m_autoscrollController->updateAutoscrollRenderer();
    205 }
    206 
    207 void Page::updateDragAndDrop(Node* dropTargetNode, const IntPoint& eventPosition, double eventTime)
    208 {
    209     m_autoscrollController->updateDragAndDrop(dropTargetNode, eventPosition, eventTime);
    210 }
    211 
    212 #if OS(WINDOWS)
    213 void Page::handleMouseReleaseForPanScrolling(Frame* frame, const PlatformMouseEvent& point)
    214 {
    215     m_autoscrollController->handleMouseReleaseForPanScrolling(frame, point);
    216 }
    217 
    218 void Page::startPanScrolling(RenderBox* renderer, const IntPoint& point)
    219 {
    220     m_autoscrollController->startPanScrolling(renderer, point);
    221 }
    222 #endif
    223 
    224 
    225 ScrollingCoordinator* Page::scrollingCoordinator()
    226 {
    227     if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
    228         m_scrollingCoordinator = ScrollingCoordinator::create(this);
    229 
    230     return m_scrollingCoordinator.get();
    231 }
    232 
    233 String Page::mainThreadScrollingReasonsAsText()
    234 {
    235     if (Document* document = m_mainFrame->document())
    236         document->updateLayout();
    237 
    238     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
    239         return scrollingCoordinator->mainThreadScrollingReasonsAsText();
    240 
    241     return String();
    242 }
    243 
    244 PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
    245 {
    246     if (Document* document = m_mainFrame->document())
    247         document->updateLayout();
    248 
    249     Vector<IntRect> rects;
    250     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
    251         rects = scrollingCoordinator->computeShouldHandleScrollGestureOnMainThreadRegion(frame, IntPoint()).rects();
    252 
    253     Vector<FloatQuad> quads(rects.size());
    254     for (size_t i = 0; i < rects.size(); ++i)
    255         quads[i] = FloatRect(rects[i]);
    256     return ClientRectList::create(quads);
    257 }
    258 
    259 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
    260 {
    261     ASSERT(!m_mainFrame); // Should only be called during initialization
    262     m_mainFrame = mainFrame;
    263 }
    264 
    265 bool Page::openedByDOM() const
    266 {
    267     return m_openedByDOM;
    268 }
    269 
    270 void Page::setOpenedByDOM()
    271 {
    272     m_openedByDOM = true;
    273 }
    274 
    275 void Page::goToItem(HistoryItem* item)
    276 {
    277     // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
    278     // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
    279     RefPtr<HistoryItem> protector(item);
    280 
    281     if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
    282         m_mainFrame->loader()->stopAllLoaders();
    283 
    284     m_mainFrame->loader()->history()->goToItem(item);
    285 }
    286 
    287 void Page::clearPageGroup()
    288 {
    289     if (!m_group)
    290         return;
    291     m_group->removePage(this);
    292     m_group = 0;
    293 }
    294 
    295 void Page::setGroupType(PageGroupType type)
    296 {
    297     clearPageGroup();
    298 
    299     switch (type) {
    300     case InspectorPageGroup:
    301         m_group = PageGroup::inspectorGroup();
    302         break;
    303     case PrivatePageGroup:
    304         m_group = PageGroup::create();
    305         break;
    306     case SharedPageGroup:
    307         m_group = PageGroup::sharedGroup();
    308         break;
    309     }
    310 
    311     m_group->addPage(this);
    312 }
    313 
    314 void Page::scheduleForcedStyleRecalcForAllPages()
    315 {
    316     if (!allPages)
    317         return;
    318     HashSet<Page*>::iterator end = allPages->end();
    319     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
    320         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
    321             frame->document()->setNeedsStyleRecalc();
    322 }
    323 
    324 void Page::setNeedsRecalcStyleInAllFrames()
    325 {
    326     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
    327         frame->document()->styleResolverChanged(DeferRecalcStyle);
    328 }
    329 
    330 void Page::refreshPlugins(bool reload)
    331 {
    332     if (!allPages)
    333         return;
    334 
    335     PluginData::refresh();
    336 
    337     Vector<RefPtr<Frame> > framesNeedingReload;
    338 
    339     HashSet<Page*>::iterator end = allPages->end();
    340     for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
    341         Page* page = *it;
    342 
    343         // Clear out the page's plug-in data.
    344         if (page->m_pluginData)
    345             page->m_pluginData = 0;
    346 
    347         if (!reload)
    348             continue;
    349 
    350         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
    351             if (frame->loader()->containsPlugins())
    352                 framesNeedingReload.append(frame);
    353         }
    354     }
    355 
    356     for (size_t i = 0; i < framesNeedingReload.size(); ++i)
    357         framesNeedingReload[i]->loader()->reload();
    358 }
    359 
    360 PluginData* Page::pluginData() const
    361 {
    362     if (!mainFrame()->loader()->allowPlugins(NotAboutToInstantiatePlugin))
    363         return 0;
    364     if (!m_pluginData)
    365         m_pluginData = PluginData::create(this);
    366     return m_pluginData.get();
    367 }
    368 
    369 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
    370 {
    371     return forward
    372         ? curr->tree()->traverseNextWithWrap(wrapFlag)
    373         : curr->tree()->traversePreviousWithWrap(wrapFlag);
    374 }
    375 
    376 void Page::unmarkAllTextMatches()
    377 {
    378     if (!mainFrame())
    379         return;
    380 
    381     Frame* frame = mainFrame();
    382     do {
    383         frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
    384         frame = incrementFrame(frame, true, false);
    385     } while (frame);
    386 }
    387 
    388 void Page::setDefersLoading(bool defers)
    389 {
    390     if (defers == m_defersLoading)
    391         return;
    392 
    393     m_defersLoading = defers;
    394     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
    395         frame->loader()->setDefersLoading(defers);
    396 }
    397 
    398 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
    399 {
    400     FrameView* view = mainFrame()->view();
    401 
    402     if (scale != m_pageScaleFactor) {
    403         m_pageScaleFactor = scale;
    404 
    405         if (view)
    406             view->setVisibleContentScaleFactor(scale);
    407 
    408         mainFrame()->deviceOrPageScaleFactorChanged();
    409 
    410         if (view)
    411             view->setViewportConstrainedObjectsNeedLayout();
    412     }
    413 
    414     if (view && view->scrollPosition() != origin)
    415         view->notifyScrollPositionChanged(origin);
    416 }
    417 
    418 void Page::setDeviceScaleFactor(float scaleFactor)
    419 {
    420     if (m_deviceScaleFactor == scaleFactor)
    421         return;
    422 
    423     m_deviceScaleFactor = scaleFactor;
    424     setNeedsRecalcStyleInAllFrames();
    425 
    426     if (mainFrame())
    427         mainFrame()->deviceOrPageScaleFactorChanged();
    428 }
    429 
    430 void Page::setPagination(const Pagination& pagination)
    431 {
    432     if (m_pagination == pagination)
    433         return;
    434 
    435     m_pagination = pagination;
    436 
    437     setNeedsRecalcStyleInAllFrames();
    438 }
    439 
    440 void Page::userStyleSheetLocationChanged()
    441 {
    442     // FIXME: Eventually we will move to a model of just being handed the sheet
    443     // text instead of loading the URL ourselves.
    444     KURL url = m_settings->userStyleSheetLocation();
    445 
    446     m_didLoadUserStyleSheet = false;
    447     m_userStyleSheet = String();
    448 
    449     // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
    450     // synchronously and avoid using a loader.
    451     if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
    452         m_didLoadUserStyleSheet = true;
    453 
    454         Vector<char> styleSheetAsUTF8;
    455         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
    456             m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
    457     }
    458 
    459     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
    460         if (frame->document())
    461             frame->document()->styleSheetCollection()->updatePageUserSheet();
    462     }
    463 }
    464 
    465 const String& Page::userStyleSheet() const
    466 {
    467     return m_userStyleSheet;
    468 }
    469 
    470 void Page::allVisitedStateChanged(PageGroup* group)
    471 {
    472     ASSERT(group);
    473     if (!allPages)
    474         return;
    475 
    476     HashSet<Page*>::iterator pagesEnd = allPages->end();
    477     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
    478         Page* page = *it;
    479         if (page->m_group != group)
    480             continue;
    481         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
    482             frame->document()->visitedLinkState()->invalidateStyleForAllLinks();
    483     }
    484 }
    485 
    486 void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash)
    487 {
    488     ASSERT(group);
    489     if (!allPages)
    490         return;
    491 
    492     HashSet<Page*>::iterator pagesEnd = allPages->end();
    493     for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
    494         Page* page = *it;
    495         if (page->m_group != group)
    496             continue;
    497         for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
    498             frame->document()->visitedLinkState()->invalidateStyleForLink(linkHash);
    499     }
    500 }
    501 
    502 StorageNamespace* Page::sessionStorage(bool optionalCreate)
    503 {
    504     if (!m_sessionStorage && optionalCreate)
    505         m_sessionStorage = StorageNamespace::sessionStorageNamespace(this);
    506     return m_sessionStorage.get();
    507 }
    508 
    509 void Page::setTimerAlignmentInterval(double interval)
    510 {
    511     if (interval == m_timerAlignmentInterval)
    512         return;
    513 
    514     m_timerAlignmentInterval = interval;
    515     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
    516         if (frame->document())
    517             frame->document()->didChangeTimerAlignmentInterval();
    518     }
    519 }
    520 
    521 double Page::timerAlignmentInterval() const
    522 {
    523     return m_timerAlignmentInterval;
    524 }
    525 
    526 void Page::dnsPrefetchingStateChanged()
    527 {
    528     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
    529         frame->document()->initDNSPrefetch();
    530 }
    531 
    532 #if !ASSERT_DISABLED
    533 void Page::checkSubframeCountConsistency() const
    534 {
    535     ASSERT(m_subframeCount >= 0);
    536 
    537     int subframeCount = 0;
    538     for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
    539         ++subframeCount;
    540 
    541     ASSERT(m_subframeCount + 1 == subframeCount);
    542 }
    543 #endif
    544 
    545 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
    546 {
    547     if (m_visibilityState == visibilityState)
    548         return;
    549     m_visibilityState = visibilityState;
    550 
    551     if (visibilityState == WebCore::PageVisibilityStateHidden)
    552         setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
    553     else
    554         setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
    555 
    556     if (!isInitialState)
    557         lifecycleNotifier()->notifyPageVisibilityChanged();
    558 
    559     if (!isInitialState && m_mainFrame)
    560         m_mainFrame->dispatchVisibilityStateChangeEvent();
    561 }
    562 
    563 PageVisibilityState Page::visibilityState() const
    564 {
    565     return m_visibilityState;
    566 }
    567 
    568 void Page::addLayoutMilestones(LayoutMilestones milestones)
    569 {
    570     // In the future, we may want a function that replaces m_layoutMilestones instead of just adding to it.
    571     m_layoutMilestones |= milestones;
    572 }
    573 
    574 // These are magical constants that might be tweaked over time.
    575 static double gMinimumPaintedAreaRatio = 0.1;
    576 static double gMaximumUnpaintedAreaRatio = 0.04;
    577 
    578 bool Page::isCountingRelevantRepaintedObjects() const
    579 {
    580     return m_isCountingRelevantRepaintedObjects && (m_layoutMilestones & DidHitRelevantRepaintedObjectsAreaThreshold);
    581 }
    582 
    583 void Page::startCountingRelevantRepaintedObjects()
    584 {
    585     // Reset everything in case we didn't hit the threshold last time.
    586     resetRelevantPaintedObjectCounter();
    587 
    588     m_isCountingRelevantRepaintedObjects = true;
    589 }
    590 
    591 void Page::resetRelevantPaintedObjectCounter()
    592 {
    593     m_isCountingRelevantRepaintedObjects = false;
    594     m_relevantUnpaintedRenderObjects.clear();
    595     m_topRelevantPaintedRegion = Region();
    596     m_bottomRelevantPaintedRegion = Region();
    597     m_relevantUnpaintedRegion = Region();
    598 }
    599 
    600 static LayoutRect relevantViewRect(RenderView* view)
    601 {
    602     // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
    603     // a certain relevant amount of content has been drawn to the screen. This is the rect that
    604     // has been determined to be relevant in the context of this goal. We may choose to tweak
    605     // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
    606     // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
    607     LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);
    608 
    609     LayoutRect viewRect = view->viewRect();
    610     // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
    611     if (viewRect.width() > relevantViewRect.width())
    612         relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);
    613 
    614     return relevantViewRect;
    615 }
    616 
    617 void Page::addRelevantRepaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
    618 {
    619     if (!isCountingRelevantRepaintedObjects())
    620         return;
    621 
    622     // Objects inside sub-frames are not considered to be relevant.
    623     if (object->document()->frame() != mainFrame())
    624         return;
    625 
    626     RenderView* view = object->view();
    627     if (!view)
    628         return;
    629 
    630     LayoutRect relevantRect = relevantViewRect(view);
    631 
    632     // The objects are only relevant if they are being painted within the viewRect().
    633     if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantRect)))
    634         return;
    635 
    636     IntRect snappedPaintRect = pixelSnappedIntRect(objectPaintRect);
    637 
    638     // If this object was previously counted as an unpainted object, remove it from that HashSet
    639     // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
    640     HashSet<RenderObject*>::iterator it = m_relevantUnpaintedRenderObjects.find(object);
    641     if (it != m_relevantUnpaintedRenderObjects.end()) {
    642         m_relevantUnpaintedRenderObjects.remove(it);
    643         m_relevantUnpaintedRegion.subtract(snappedPaintRect);
    644     }
    645 
    646     // Split the relevantRect into a top half and a bottom half. Making sure we have coverage in
    647     // both halves helps to prevent cases where we have a fully loaded menu bar or masthead with
    648     // no content beneath that.
    649     LayoutRect topRelevantRect = relevantRect;
    650     topRelevantRect.contract(LayoutSize(0, relevantRect.height() / 2));
    651     LayoutRect bottomRelevantRect = topRelevantRect;
    652     bottomRelevantRect.setY(relevantRect.height() / 2);
    653 
    654     // If the rect straddles both Regions, split it appropriately.
    655     if (topRelevantRect.intersects(snappedPaintRect) && bottomRelevantRect.intersects(snappedPaintRect)) {
    656         IntRect topIntersection = snappedPaintRect;
    657         topIntersection.intersect(pixelSnappedIntRect(topRelevantRect));
    658         m_topRelevantPaintedRegion.unite(topIntersection);
    659 
    660         IntRect bottomIntersection = snappedPaintRect;
    661         bottomIntersection.intersect(pixelSnappedIntRect(bottomRelevantRect));
    662         m_bottomRelevantPaintedRegion.unite(bottomIntersection);
    663     } else if (topRelevantRect.intersects(snappedPaintRect))
    664         m_topRelevantPaintedRegion.unite(snappedPaintRect);
    665     else
    666         m_bottomRelevantPaintedRegion.unite(snappedPaintRect);
    667 
    668     float topPaintedArea = m_topRelevantPaintedRegion.totalArea();
    669     float bottomPaintedArea = m_bottomRelevantPaintedRegion.totalArea();
    670     float viewArea = relevantRect.width() * relevantRect.height();
    671 
    672     float ratioThatIsPaintedOnTop = topPaintedArea / viewArea;
    673     float ratioThatIsPaintedOnBottom = bottomPaintedArea / viewArea;
    674     float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
    675 
    676     if (ratioThatIsPaintedOnTop > (gMinimumPaintedAreaRatio / 2) && ratioThatIsPaintedOnBottom > (gMinimumPaintedAreaRatio / 2)
    677         && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
    678         m_isCountingRelevantRepaintedObjects = false;
    679         resetRelevantPaintedObjectCounter();
    680         if (Frame* frame = mainFrame())
    681             frame->loader()->didLayout(DidHitRelevantRepaintedObjectsAreaThreshold);
    682     }
    683 }
    684 
    685 void Page::addRelevantUnpaintedObject(RenderObject* object, const LayoutRect& objectPaintRect)
    686 {
    687     if (!isCountingRelevantRepaintedObjects())
    688         return;
    689 
    690     // The objects are only relevant if they are being painted within the relevantViewRect().
    691     if (RenderView* view = object->view()) {
    692         if (!objectPaintRect.intersects(pixelSnappedIntRect(relevantViewRect(view))))
    693             return;
    694     }
    695 
    696     m_relevantUnpaintedRenderObjects.add(object);
    697     m_relevantUnpaintedRegion.unite(pixelSnappedIntRect(objectPaintRect));
    698 }
    699 
    700 void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
    701 {
    702     m_multisamplingChangedObservers.add(observer);
    703 }
    704 
    705 void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
    706 {
    707     m_multisamplingChangedObservers.remove(observer);
    708 }
    709 
    710 void Page::multisamplingChanged()
    711 {
    712     HashSet<MultisamplingChangedObserver*>::iterator stop = m_multisamplingChangedObservers.end();
    713     for (HashSet<MultisamplingChangedObserver*>::iterator it = m_multisamplingChangedObservers.begin(); it != stop; ++it)
    714         (*it)->multisamplingChanged(m_settings->openGLMultisamplingEnabled());
    715 }
    716 
    717 void Page::didCommitLoad(Frame* frame)
    718 {
    719     lifecycleNotifier()->notifyDidCommitLoad(frame);
    720 }
    721 
    722 PageLifecycleNotifier* Page::lifecycleNotifier()
    723 {
    724     return static_cast<PageLifecycleNotifier*>(LifecycleContext::lifecycleNotifier());
    725 }
    726 
    727 PassOwnPtr<LifecycleNotifier> Page::createLifecycleNotifier()
    728 {
    729     return PageLifecycleNotifier::create(this);
    730 }
    731 
    732 Page::PageClients::PageClients()
    733     : chromeClient(0)
    734     , contextMenuClient(0)
    735     , editorClient(0)
    736     , dragClient(0)
    737     , inspectorClient(0)
    738 {
    739 }
    740 
    741 Page::PageClients::~PageClients()
    742 {
    743 }
    744 
    745 } // namespace WebCore
    746