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