1 /* 2 * Copyright (C) 1998, 1999 Torben Weis <weis (at) kde.org> 3 * 1999 Lars Knoll <knoll (at) kde.org> 4 * 1999 Antti Koivisto <koivisto (at) kde.org> 5 * 2000 Dirk Mueller <mueller (at) kde.org> 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 7 * (C) 2006 Graham Dennis (graham.dennis (at) gmail.com) 8 * (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 9 * Copyright (C) 2009 Google Inc. All rights reserved. 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Library General Public 13 * License as published by the Free Software Foundation; either 14 * version 2 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Library General Public License for more details. 20 * 21 * You should have received a copy of the GNU Library General Public License 22 * along with this library; see the file COPYING.LIB. If not, write to 23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 * Boston, MA 02110-1301, USA. 25 */ 26 27 #include "config.h" 28 #include "core/frame/FrameView.h" 29 30 #include "HTMLNames.h" 31 #include "RuntimeEnabledFeatures.h" 32 #include "core/accessibility/AXObjectCache.h" 33 #include "core/animation/DocumentAnimations.h" 34 #include "core/css/FontFaceSet.h" 35 #include "core/css/resolver/StyleResolver.h" 36 #include "core/dom/DocumentMarkerController.h" 37 #include "core/editing/FrameSelection.h" 38 #include "core/events/OverflowEvent.h" 39 #include "core/fetch/ResourceFetcher.h" 40 #include "core/fetch/ResourceLoadPriorityOptimizer.h" 41 #include "core/fetch/TextResourceDecoder.h" 42 #include "core/frame/Frame.h" 43 #include "core/frame/GraphicsLayerDebugInfo.h" 44 #include "core/frame/Settings.h" 45 #include "core/frame/animation/AnimationController.h" 46 #include "core/html/HTMLFrameElement.h" 47 #include "core/html/HTMLHtmlElement.h" 48 #include "core/html/HTMLPlugInElement.h" 49 #include "core/inspector/InspectorInstrumentation.h" 50 #include "core/loader/FrameLoader.h" 51 #include "core/loader/FrameLoaderClient.h" 52 #include "core/page/Chrome.h" 53 #include "core/page/ChromeClient.h" 54 #include "core/page/EventHandler.h" 55 #include "core/page/FocusController.h" 56 #include "core/page/FrameTree.h" 57 #include "core/page/scrolling/ScrollingCoordinator.h" 58 #include "core/rendering/CompositedLayerMapping.h" 59 #include "core/rendering/LayoutIndicator.h" 60 #include "core/rendering/RenderCounter.h" 61 #include "core/rendering/RenderEmbeddedObject.h" 62 #include "core/rendering/RenderLayer.h" 63 #include "core/rendering/RenderLayerCompositor.h" 64 #include "core/rendering/RenderPart.h" 65 #include "core/rendering/RenderScrollbar.h" 66 #include "core/rendering/RenderScrollbarPart.h" 67 #include "core/rendering/RenderTheme.h" 68 #include "core/rendering/RenderView.h" 69 #include "core/rendering/TextAutosizer.h" 70 #include "core/rendering/style/RenderStyle.h" 71 #include "core/rendering/svg/RenderSVGRoot.h" 72 #include "core/svg/SVGDocument.h" 73 #include "core/svg/SVGSVGElement.h" 74 #include "platform/TraceEvent.h" 75 #include "platform/fonts/FontCache.h" 76 #include "platform/geometry/FloatRect.h" 77 #include "platform/graphics/GraphicsContext.h" 78 #include "platform/scroll/ScrollAnimator.h" 79 #include "platform/scroll/ScrollbarTheme.h" 80 #include "platform/text/TextStream.h" 81 #include "wtf/CurrentTime.h" 82 #include "wtf/TemporaryChange.h" 83 84 namespace WebCore { 85 86 using namespace HTMLNames; 87 88 double FrameView::s_currentFrameTimeStamp = 0.0; 89 bool FrameView::s_inPaintContents = false; 90 91 92 // REPAINT_THROTTLING now chooses default values for throttling parameters. 93 // Should be removed when applications start using runtime configuration. 94 #if ENABLE(REPAINT_THROTTLING) 95 // Normal delay 96 double FrameView::s_normalDeferredRepaintDelay = 0.016; 97 // Negative value would mean that first few repaints happen without a delay 98 double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0; 99 // The delay grows on each repaint to this maximum value 100 double FrameView::s_maxDeferredRepaintDelayDuringLoading = 2.5; 101 // On each repaint the delay increses by this amount 102 double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0.5; 103 #else 104 // FIXME: Repaint throttling could be good to have on all platform. 105 // The balance between CPU use and repaint frequency will need some tuning for desktop. 106 // More hooks may be needed to reset the delay on things like GIF and CSS animations. 107 double FrameView::s_normalDeferredRepaintDelay = 0; 108 double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0; 109 double FrameView::s_maxDeferredRepaintDelayDuringLoading = 0; 110 double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0; 111 #endif 112 113 // The maximum number of updateWidgets iterations that should be done before returning. 114 static const unsigned maxUpdateWidgetsIterations = 2; 115 116 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint) 117 { 118 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags; 119 120 if (didFullRepaint) { 121 flags &= ~RenderLayer::CheckForRepaint; 122 flags |= RenderLayer::NeedsFullRepaintInBacking; 123 } 124 if (isRelayoutingSubtree && layer->isPaginated()) 125 flags |= RenderLayer::UpdatePagination; 126 return flags; 127 } 128 129 Pagination::Mode paginationModeForRenderStyle(RenderStyle* style) 130 { 131 EOverflow overflow = style->overflowY(); 132 if (overflow != OPAGEDX && overflow != OPAGEDY) 133 return Pagination::Unpaginated; 134 135 bool isHorizontalWritingMode = style->isHorizontalWritingMode(); 136 TextDirection textDirection = style->direction(); 137 WritingMode writingMode = style->writingMode(); 138 139 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode 140 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode 141 // is vertical, then the direction of the verticality dictates the choice. 142 if (overflow == OPAGEDX) { 143 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode) 144 return Pagination::LeftToRightPaginated; 145 return Pagination::RightToLeftPaginated; 146 } 147 148 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode 149 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode 150 // is vertical, then we use TextDirection to choose between those options. 151 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL)) 152 return Pagination::TopToBottomPaginated; 153 return Pagination::BottomToTopPaginated; 154 } 155 156 FrameView::DeferredRepaintScope::DeferredRepaintScope(FrameView& view) 157 : m_view(&view) 158 { 159 m_view->beginDeferredRepaints(); 160 } 161 162 FrameView::DeferredRepaintScope::~DeferredRepaintScope() 163 { 164 m_view->endDeferredRepaints(); 165 } 166 167 FrameView::FrameView(Frame* frame) 168 : m_frame(frame) 169 , m_canHaveScrollbars(true) 170 , m_slowRepaintObjectCount(0) 171 , m_layoutTimer(this, &FrameView::layoutTimerFired) 172 , m_layoutRoot(0) 173 , m_inSynchronousPostLayout(false) 174 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) 175 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired) 176 , m_isTransparent(false) 177 , m_baseBackgroundColor(Color::white) 178 , m_mediaType("screen") 179 , m_overflowStatusDirty(true) 180 , m_viewportRenderer(0) 181 , m_wasScrolledByUser(false) 182 , m_inProgrammaticScroll(false) 183 , m_safeToPropagateScrollToParent(true) 184 , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired) 185 , m_isTrackingRepaints(false) 186 , m_shouldUpdateWhileOffscreen(true) 187 , m_scrollCorner(0) 188 , m_shouldAutoSize(false) 189 , m_inAutoSize(false) 190 , m_didRunAutosize(false) 191 , m_hasSoftwareFilters(false) 192 , m_visibleContentScaleFactor(1) 193 , m_inputEventsScaleFactorForEmulation(1) 194 , m_partialLayout() 195 , m_layoutSizeFixedToFrameSize(true) 196 { 197 ASSERT(m_frame); 198 init(); 199 200 if (!isMainFrame()) 201 return; 202 203 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed); 204 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed); 205 } 206 207 PassRefPtr<FrameView> FrameView::create(Frame* frame) 208 { 209 RefPtr<FrameView> view = adoptRef(new FrameView(frame)); 210 view->show(); 211 return view.release(); 212 } 213 214 PassRefPtr<FrameView> FrameView::create(Frame* frame, const IntSize& initialSize) 215 { 216 RefPtr<FrameView> view = adoptRef(new FrameView(frame)); 217 view->Widget::setFrameRect(IntRect(view->location(), initialSize)); 218 view->setLayoutSizeInternal(initialSize); 219 220 view->show(); 221 return view.release(); 222 } 223 224 FrameView::~FrameView() 225 { 226 if (m_postLayoutTasksTimer.isActive()) 227 m_postLayoutTasksTimer.stop(); 228 229 removeFromAXObjectCache(); 230 resetScrollbars(); 231 232 // Custom scrollbars should already be destroyed at this point 233 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar()); 234 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar()); 235 236 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow. 237 setHasVerticalScrollbar(false); 238 239 ASSERT(!m_scrollCorner); 240 241 ASSERT(m_frame); 242 ASSERT(m_frame->view() != this || !m_frame->contentRenderer()); 243 RenderPart* renderer = m_frame->ownerRenderer(); 244 if (renderer && renderer->widget() == this) 245 renderer->setWidget(0); 246 } 247 248 void FrameView::reset() 249 { 250 m_cannotBlitToWindow = false; 251 m_isOverlapped = false; 252 m_contentIsOpaque = false; 253 m_borderX = 30; 254 m_borderY = 30; 255 m_layoutTimer.stop(); 256 m_layoutRoot = 0; 257 m_delayedLayout = false; 258 m_doFullRepaint = true; 259 m_layoutSchedulingEnabled = true; 260 m_inLayout = false; 261 m_doingPreLayoutStyleUpdate = false; 262 m_inSynchronousPostLayout = false; 263 m_layoutCount = 0; 264 m_nestedLayoutCount = 0; 265 m_postLayoutTasksTimer.stop(); 266 m_updateWidgetsTimer.stop(); 267 m_firstLayout = true; 268 m_firstLayoutCallbackPending = false; 269 m_wasScrolledByUser = false; 270 m_safeToPropagateScrollToParent = true; 271 m_lastViewportSize = IntSize(); 272 m_lastZoomFactor = 1.0f; 273 m_deferringRepaints = 0; 274 m_repaintCount = 0; 275 m_repaintRects.clear(); 276 m_deferredRepaintDelay = s_initialDeferredRepaintDelayDuringLoading; 277 m_deferredRepaintTimer.stop(); 278 m_isTrackingRepaints = false; 279 m_trackedRepaintRects.clear(); 280 m_lastPaintTime = 0; 281 m_paintBehavior = PaintBehaviorNormal; 282 m_isPainting = false; 283 m_visuallyNonEmptyCharacterCount = 0; 284 m_visuallyNonEmptyPixelCount = 0; 285 m_isVisuallyNonEmpty = false; 286 m_firstVisuallyNonEmptyLayoutCallbackPending = true; 287 m_maintainScrollPositionAnchor = 0; 288 m_partialLayout.reset(); 289 m_viewportConstrainedObjects.clear(); 290 } 291 292 void FrameView::removeFromAXObjectCache() 293 { 294 if (AXObjectCache* cache = axObjectCache()) 295 cache->remove(this); 296 } 297 298 void FrameView::resetScrollbars() 299 { 300 // Reset the document's scrollbars back to our defaults before we yield the floor. 301 m_firstLayout = true; 302 setScrollbarsSuppressed(true); 303 if (m_canHaveScrollbars) 304 setScrollbarModes(ScrollbarAuto, ScrollbarAuto); 305 else 306 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); 307 setScrollbarsSuppressed(false); 308 } 309 310 void FrameView::init() 311 { 312 reset(); 313 314 m_margins = LayoutSize(-1, -1); // undefined 315 m_size = LayoutSize(); 316 317 // Propagate the marginwidth/height and scrolling modes to the view. 318 Element* ownerElement = m_frame->ownerElement(); 319 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { 320 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement); 321 if (frameElt->scrollingMode() == ScrollbarAlwaysOff) 322 setCanHaveScrollbars(false); 323 LayoutUnit marginWidth = frameElt->marginWidth(); 324 LayoutUnit marginHeight = frameElt->marginHeight(); 325 if (marginWidth != -1) 326 setMarginWidth(marginWidth); 327 if (marginHeight != -1) 328 setMarginHeight(marginHeight); 329 } 330 } 331 332 void FrameView::prepareForDetach() 333 { 334 RELEASE_ASSERT(!isInLayout()); 335 336 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) 337 scrollAnimator->cancelAnimations(); 338 339 detachCustomScrollbars(); 340 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache 341 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later. 342 removeFromAXObjectCache(); 343 344 if (m_frame->page()) { 345 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) 346 scrollingCoordinator->willDestroyScrollableArea(this); 347 } 348 } 349 350 void FrameView::detachCustomScrollbars() 351 { 352 Scrollbar* horizontalBar = horizontalScrollbar(); 353 if (horizontalBar && horizontalBar->isCustomScrollbar()) 354 setHasHorizontalScrollbar(false); 355 356 Scrollbar* verticalBar = verticalScrollbar(); 357 if (verticalBar && verticalBar->isCustomScrollbar()) 358 setHasVerticalScrollbar(false); 359 360 if (m_scrollCorner) { 361 m_scrollCorner->destroy(); 362 m_scrollCorner = 0; 363 } 364 } 365 366 void FrameView::recalculateScrollbarOverlayStyle() 367 { 368 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle(); 369 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; 370 371 Color backgroundColor = documentBackgroundColor(); 372 if (backgroundColor.isValid()) { 373 // Reduce the background color from RGB to a lightness value 374 // and determine which scrollbar style to use based on a lightness 375 // heuristic. 376 double hue, saturation, lightness; 377 backgroundColor.getHSL(hue, saturation, lightness); 378 if (lightness <= .5) 379 overlayStyle = ScrollbarOverlayStyleLight; 380 } 381 382 if (oldOverlayStyle != overlayStyle) 383 setScrollbarOverlayStyle(overlayStyle); 384 } 385 386 void FrameView::clear() 387 { 388 setCanBlitOnScroll(true); 389 390 reset(); 391 392 if (RenderPart* renderer = m_frame->ownerRenderer()) 393 renderer->viewCleared(); 394 395 setScrollbarsSuppressed(true); 396 } 397 398 bool FrameView::didFirstLayout() const 399 { 400 return !m_firstLayout; 401 } 402 403 void FrameView::invalidateRect(const IntRect& rect) 404 { 405 if (!parent()) { 406 if (HostWindow* window = hostWindow()) 407 window->invalidateContentsAndRootView(rect); 408 return; 409 } 410 411 RenderPart* renderer = m_frame->ownerRenderer(); 412 if (!renderer) 413 return; 414 415 IntRect repaintRect = rect; 416 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), 417 renderer->borderTop() + renderer->paddingTop()); 418 renderer->repaintRectangle(repaintRect); 419 } 420 421 void FrameView::setFrameRect(const IntRect& newRect) 422 { 423 IntRect oldRect = frameRect(); 424 if (newRect == oldRect) 425 return; 426 427 // Autosized font sizes depend on the width of the viewing area. 428 if (newRect.width() != oldRect.width()) { 429 Page* page = m_frame->page(); 430 if (isMainFrame() && page->settings().textAutosizingEnabled()) { 431 TextAutosizer* textAutosizer = m_frame->document()->textAutosizer(); 432 if (textAutosizer) { 433 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) 434 textAutosizer->recalculateMultipliers(); 435 } 436 } 437 } 438 439 ScrollView::setFrameRect(newRect); 440 441 updateScrollableAreaSet(); 442 443 if (RenderView* renderView = this->renderView()) { 444 if (renderView->usesCompositing()) 445 renderView->compositor()->frameViewDidChangeSize(); 446 } 447 } 448 449 bool FrameView::scheduleAnimation() 450 { 451 if (HostWindow* window = hostWindow()) { 452 window->scheduleAnimation(); 453 return true; 454 } 455 return false; 456 } 457 458 RenderView* FrameView::renderView() const 459 { 460 return frame().contentRenderer(); 461 } 462 463 void FrameView::setMarginWidth(LayoutUnit w) 464 { 465 // make it update the rendering area when set 466 m_margins.setWidth(w); 467 } 468 469 void FrameView::setMarginHeight(LayoutUnit h) 470 { 471 // make it update the rendering area when set 472 m_margins.setHeight(h); 473 } 474 475 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) 476 { 477 m_canHaveScrollbars = canHaveScrollbars; 478 ScrollView::setCanHaveScrollbars(canHaveScrollbars); 479 } 480 481 void FrameView::updateCanHaveScrollbars() 482 { 483 ScrollbarMode hMode; 484 ScrollbarMode vMode; 485 scrollbarModes(hMode, vMode); 486 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff) 487 setCanHaveScrollbars(false); 488 else 489 setCanHaveScrollbars(true); 490 } 491 492 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, Frame*& customScrollbarFrame) 493 { 494 customScrollbarElement = 0; 495 customScrollbarFrame = 0; 496 497 if (Settings* settings = m_frame->settings()) { 498 if (!settings->allowCustomScrollbarInMainFrame() && isMainFrame()) 499 return false; 500 } 501 502 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). 503 Document* doc = m_frame->document(); 504 505 // Try the <body> element first as a scrollbar source. 506 Element* body = doc ? doc->body() : 0; 507 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) { 508 customScrollbarElement = body; 509 return true; 510 } 511 512 // If the <body> didn't have a custom style, then the root element might. 513 Element* docElement = doc ? doc->documentElement() : 0; 514 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) { 515 customScrollbarElement = docElement; 516 return true; 517 } 518 519 // If we have an owning ipage/Frame element, then it can set the custom scrollbar also. 520 RenderPart* frameRenderer = m_frame->ownerRenderer(); 521 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) { 522 customScrollbarFrame = m_frame.get(); 523 return true; 524 } 525 526 return false; 527 } 528 529 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) 530 { 531 Element* customScrollbarElement = 0; 532 Frame* customScrollbarFrame = 0; 533 if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame)) 534 return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame); 535 536 // Nobody set a custom style, so we just use a native scrollbar. 537 return ScrollView::createScrollbar(orientation); 538 } 539 540 void FrameView::setContentsSize(const IntSize& size) 541 { 542 if (size == contentsSize()) 543 return; 544 545 ScrollView::setContentsSize(size); 546 ScrollView::contentsResized(); 547 548 Page* page = frame().page(); 549 if (!page) 550 return; 551 552 updateScrollableAreaSet(); 553 554 page->chrome().contentsSizeChanged(m_frame.get(), size); 555 } 556 557 void FrameView::adjustViewSize() 558 { 559 RenderView* renderView = this->renderView(); 560 if (!renderView) 561 return; 562 563 ASSERT(m_frame->view() == this); 564 565 const IntRect rect = renderView->documentRect(); 566 const IntSize& size = rect.size(); 567 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize()); 568 569 setContentsSize(size); 570 } 571 572 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode) 573 { 574 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats 575 // overflow:hidden and overflow:scroll on <body> as applying to the document's 576 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should 577 // use the root element. 578 579 EOverflow overflowX = o->style()->overflowX(); 580 EOverflow overflowY = o->style()->overflowY(); 581 582 if (o->isSVGRoot()) { 583 // overflow is ignored in stand-alone SVG documents. 584 if (!toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) 585 return; 586 overflowX = OHIDDEN; 587 overflowY = OHIDDEN; 588 } 589 590 bool ignoreOverflowHidden = false; 591 if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame()) 592 ignoreOverflowHidden = true; 593 594 switch (overflowX) { 595 case OHIDDEN: 596 if (!ignoreOverflowHidden) 597 hMode = ScrollbarAlwaysOff; 598 break; 599 case OSCROLL: 600 hMode = ScrollbarAlwaysOn; 601 break; 602 case OAUTO: 603 hMode = ScrollbarAuto; 604 break; 605 default: 606 // Don't set it at all. 607 ; 608 } 609 610 switch (overflowY) { 611 case OHIDDEN: 612 if (!ignoreOverflowHidden) 613 vMode = ScrollbarAlwaysOff; 614 break; 615 case OSCROLL: 616 vMode = ScrollbarAlwaysOn; 617 break; 618 case OAUTO: 619 vMode = ScrollbarAuto; 620 break; 621 default: 622 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort(). 623 ; 624 } 625 626 m_viewportRenderer = o; 627 } 628 629 void FrameView::applyPaginationToViewport() 630 { 631 Document* document = m_frame->document(); 632 Node* documentElement = document->documentElement(); 633 RenderObject* documentRenderer = documentElement ? documentElement->renderer() : 0; 634 RenderObject* documentOrBodyRenderer = documentRenderer; 635 Node* body = document->body(); 636 if (body && body->renderer()) { 637 if (body->hasTagName(bodyTag)) 638 documentOrBodyRenderer = documentRenderer->style()->overflowX() == OVISIBLE && isHTMLHtmlElement(documentElement) ? body->renderer() : documentRenderer; 639 } 640 641 Pagination pagination; 642 643 if (!documentOrBodyRenderer) { 644 setPagination(pagination); 645 return; 646 } 647 648 EOverflow overflowY = documentOrBodyRenderer->style()->overflowY(); 649 if (overflowY == OPAGEDX || overflowY == OPAGEDY) { 650 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style()); 651 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style()->columnGap()); 652 } 653 654 setPagination(pagination); 655 } 656 657 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy) 658 { 659 m_viewportRenderer = 0; 660 661 const HTMLFrameOwnerElement* owner = m_frame->ownerElement(); 662 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) { 663 hMode = ScrollbarAlwaysOff; 664 vMode = ScrollbarAlwaysOff; 665 return; 666 } 667 668 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { 669 hMode = ScrollbarAuto; 670 // Seamless documents begin with heights of 0; we special case that here 671 // to correctly render documents that don't need scrollbars. 672 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size(); 673 bool isSeamlessDocument = frame().document() && frame().document()->shouldDisplaySeamlesslyWithParent(); 674 vMode = (isSeamlessDocument && !fullVisibleSize.height()) ? ScrollbarAlwaysOff : ScrollbarAuto; 675 } else { 676 hMode = ScrollbarAlwaysOff; 677 vMode = ScrollbarAlwaysOff; 678 } 679 680 if (!m_layoutRoot) { 681 Document* document = m_frame->document(); 682 Node* documentElement = document->documentElement(); 683 RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0; 684 Node* body = document->body(); 685 if (body && body->renderer()) { 686 if (body->hasTagName(framesetTag)) { 687 vMode = ScrollbarAlwaysOff; 688 hMode = ScrollbarAlwaysOff; 689 } else if (body->hasTagName(bodyTag)) { 690 // It's sufficient to just check the X overflow, 691 // since it's illegal to have visible in only one direction. 692 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && isHTMLHtmlElement(document->documentElement()) ? body->renderer() : rootRenderer; 693 if (o->style()) 694 applyOverflowToViewport(o, hMode, vMode); 695 } 696 } else if (rootRenderer) 697 applyOverflowToViewport(rootRenderer, hMode, vMode); 698 } 699 } 700 701 void FrameView::updateCompositingLayersAfterStyleChange() 702 { 703 TRACE_EVENT0("webkit", "FrameView::updateCompositingLayersAfterStyleChange"); 704 RenderView* renderView = this->renderView(); 705 if (!renderView) 706 return; 707 708 // If we expect to update compositing after an incipient layout, don't do so here. 709 if (m_doingPreLayoutStyleUpdate || layoutPending() || renderView->needsLayout()) 710 return; 711 712 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref 713 renderView->compositor()->cacheAcceleratedCompositingFlags(); 714 715 // Sometimes we will change a property (for example, z-index) that will not 716 // cause a layout, but will require us to update compositing state. We only 717 // need to do this if a layout is not already scheduled. 718 if (!needsLayout()) 719 renderView->compositor()->updateCompositingRequirementsState(); 720 721 renderView->compositor()->updateCompositingLayers(CompositingUpdateAfterStyleChange); 722 } 723 724 void FrameView::updateCompositingLayersAfterLayout() 725 { 726 TRACE_EVENT0("webkit", "FrameView::updateCompositingLayersAfterLayout"); 727 RenderView* renderView = this->renderView(); 728 if (!renderView) 729 return; 730 731 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref 732 renderView->compositor()->cacheAcceleratedCompositingFlags(); 733 renderView->compositor()->updateCompositingRequirementsState(); 734 renderView->compositor()->updateCompositingLayers(CompositingUpdateAfterLayout); 735 } 736 737 bool FrameView::usesCompositedScrolling() const 738 { 739 RenderView* renderView = this->renderView(); 740 if (!renderView) 741 return false; 742 if (m_frame->settings() && m_frame->settings()->compositedScrollingForFramesEnabled()) 743 return renderView->compositor()->inForcedCompositingMode(); 744 return false; 745 } 746 747 GraphicsLayer* FrameView::layerForScrolling() const 748 { 749 RenderView* renderView = this->renderView(); 750 if (!renderView) 751 return 0; 752 return renderView->compositor()->scrollLayer(); 753 } 754 755 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const 756 { 757 RenderView* renderView = this->renderView(); 758 if (!renderView) 759 return 0; 760 return renderView->compositor()->layerForHorizontalScrollbar(); 761 } 762 763 GraphicsLayer* FrameView::layerForVerticalScrollbar() const 764 { 765 RenderView* renderView = this->renderView(); 766 if (!renderView) 767 return 0; 768 return renderView->compositor()->layerForVerticalScrollbar(); 769 } 770 771 GraphicsLayer* FrameView::layerForScrollCorner() const 772 { 773 RenderView* renderView = this->renderView(); 774 if (!renderView) 775 return 0; 776 return renderView->compositor()->layerForScrollCorner(); 777 } 778 779 bool FrameView::hasCompositedContent() const 780 { 781 if (RenderView* renderView = this->renderView()) 782 return renderView->compositor()->inCompositingMode(); 783 return false; 784 } 785 786 bool FrameView::isEnclosedInCompositingLayer() const 787 { 788 RenderObject* frameOwnerRenderer = m_frame->ownerRenderer(); 789 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint()) 790 return true; 791 792 if (FrameView* parentView = parentFrameView()) 793 return parentView->isEnclosedInCompositingLayer(); 794 795 return false; 796 } 797 798 bool FrameView::isSoftwareRenderable() const 799 { 800 RenderView* renderView = this->renderView(); 801 return !renderView || !renderView->compositor()->has3DContent(); 802 } 803 804 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const 805 { 806 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; 807 } 808 809 static inline void collectFrameViewChildren(FrameView* frameView, Vector<RefPtr<FrameView> >& frameViews) 810 { 811 const HashSet<RefPtr<Widget> >* viewChildren = frameView->children(); 812 ASSERT(viewChildren); 813 814 const HashSet<RefPtr<Widget> >::iterator end = viewChildren->end(); 815 for (HashSet<RefPtr<Widget> >::iterator current = viewChildren->begin(); current != end; ++current) { 816 Widget* widget = (*current).get(); 817 if (widget->isFrameView()) 818 frameViews.append(toFrameView(widget)); 819 } 820 } 821 822 inline void FrameView::forceLayoutParentViewIfNeeded() 823 { 824 RenderPart* ownerRenderer = m_frame->ownerRenderer(); 825 if (!ownerRenderer || !ownerRenderer->frame()) 826 return; 827 828 RenderBox* contentBox = embeddedContentBox(); 829 if (!contentBox) 830 return; 831 832 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox); 833 if (svgRoot->everHadLayout() && !svgRoot->needsLayout()) 834 return; 835 836 // If the embedded SVG document appears the first time, the ownerRenderer has already finished 837 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced 838 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before 839 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its 840 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the 841 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying 842 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>). 843 RefPtr<FrameView> frameView = ownerRenderer->frame()->view(); 844 845 // Mark the owner renderer as needing layout. 846 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc(); 847 848 // Synchronously enter layout, to layout the view containing the host object/embed/iframe. 849 ASSERT(frameView); 850 frameView->layout(); 851 } 852 853 void FrameView::performPreLayoutTasks() 854 { 855 // Don't schedule more layouts, we're in one. 856 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false); 857 858 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !frame().document()->shouldDisplaySeamlesslyWithParent()) { 859 // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now. 860 m_inSynchronousPostLayout = true; 861 performPostLayoutTasks(); 862 m_inSynchronousPostLayout = false; 863 } 864 865 // Viewport-dependent media queries may cause us to need completely different style information. 866 Document* document = m_frame->document(); 867 if (!document->styleResolver() || document->styleResolver()->affectedByViewportChange()) { 868 document->styleResolverChanged(RecalcStyleDeferred); 869 document->mediaQueryAffectingValueChanged(); 870 871 // FIXME: This instrumentation event is not strictly accurate since cached media query results 872 // do not persist across StyleResolver rebuilds. 873 InspectorInstrumentation::mediaQueryResultChanged(document); 874 } else { 875 document->evaluateMediaQueryList(); 876 } 877 878 // If there is any pagination to apply, it will affect the RenderView's style, so we should 879 // take care of that now. 880 applyPaginationToViewport(); 881 882 // Always ensure our style info is up-to-date. This can happen in situations where 883 // the layout beats any sort of style recalc update that needs to occur. 884 TemporaryChange<bool> changeDoingPreLayoutStyleUpdate(m_doingPreLayoutStyleUpdate, true); 885 document->updateStyleIfNeeded(); 886 } 887 888 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout) 889 { 890 // performLayout is the actual guts of layout(). 891 // FIXME: The 300 other lines in layout() probably belong in other helper functions 892 // so that a single human could understand what layout() is actually doing. 893 FrameView::DeferredRepaintScope deferRepaints(*this); 894 895 { 896 bool disableLayoutState = false; 897 if (inSubtreeLayout) { 898 RenderView* view = rootForThisLayout->view(); 899 disableLayoutState = view->shouldDisableLayoutStateForSubtree(rootForThisLayout); 900 view->pushLayoutState(rootForThisLayout); 901 } 902 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? rootForThisLayout->view() : 0); 903 904 m_inLayout = true; 905 906 forceLayoutParentViewIfNeeded(); 907 908 // Text Autosizing requires two-pass layout which is incompatible with partial layout. 909 // If enabled, only do partial layout for the second layout. 910 // FIXME (crbug.com/256657): Do not do two layouts for text autosizing. 911 PartialLayoutDisabler partialLayoutDisabler(partialLayout(), m_frame->settings() && m_frame->settings()->textAutosizingEnabled()); 912 913 LayoutIndicator layoutIndicator; 914 rootForThisLayout->layout(); 915 gatherDebugLayoutRects(rootForThisLayout); 916 917 ResourceLoadPriorityOptimizer modifier; 918 rootForThisLayout->didLayout(modifier); 919 } 920 921 TextAutosizer* textAutosizer = frame().document()->textAutosizer(); 922 bool autosized = textAutosizer && textAutosizer->processSubtree(rootForThisLayout); 923 if (autosized && rootForThisLayout->needsLayout()) { 924 TRACE_EVENT0("webkit", "2nd layout due to Text Autosizing"); 925 LayoutIndicator layoutIndicator; 926 rootForThisLayout->layout(); 927 gatherDebugLayoutRects(rootForThisLayout); 928 929 ResourceLoadPriorityOptimizer modifier; 930 rootForThisLayout->didLayout(modifier); 931 } 932 933 m_inLayout = false; 934 935 if (inSubtreeLayout) 936 rootForThisLayout->view()->popLayoutState(rootForThisLayout); 937 } 938 939 void FrameView::scheduleOrPerformPostLayoutTasks() 940 { 941 if (m_postLayoutTasksTimer.isActive()) 942 return; 943 944 // Partial layouts should not happen with synchronous post layouts. 945 ASSERT(!(m_inSynchronousPostLayout && partialLayout().isStopping())); 946 947 if (!m_inSynchronousPostLayout) { 948 if (frame().document()->shouldDisplaySeamlesslyWithParent()) { 949 if (RenderView* renderView = this->renderView()) 950 renderView->updateWidgetPositions(); 951 } else { 952 m_inSynchronousPostLayout = true; 953 // Calls resumeScheduledEvents() 954 performPostLayoutTasks(); 955 m_inSynchronousPostLayout = false; 956 } 957 } 958 959 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || frame().document()->shouldDisplaySeamlesslyWithParent())) { 960 // If we need layout or are already in a synchronous call to postLayoutTasks(), 961 // defer widget updates and event dispatch until after we return. postLayoutTasks() 962 // can make us need to update again, and we can get stuck in a nasty cycle unless 963 // we call it through the timer here. 964 m_postLayoutTasksTimer.startOneShot(0); 965 if (!partialLayout().isStopping() && needsLayout()) 966 layout(); 967 } 968 } 969 970 void FrameView::layout(bool allowSubtree) 971 { 972 // We should never layout a Document which is not in a Frame. 973 ASSERT(m_frame); 974 ASSERT(m_frame->view() == this); 975 ASSERT(m_frame->page()); 976 977 if (m_inLayout) 978 return; 979 980 if (!m_frame->document()->isActive()) 981 return; 982 983 ASSERT(!partialLayout().isStopping()); 984 985 TRACE_EVENT0("webkit", "FrameView::layout"); 986 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "Layout"); 987 988 // Protect the view from being deleted during layout (in recalcStyle) 989 RefPtr<FrameView> protector(this); 990 991 // Every scroll that happens during layout is programmatic. 992 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); 993 994 m_layoutTimer.stop(); 995 m_delayedLayout = false; 996 997 // we shouldn't enter layout() while painting 998 ASSERT(!isPainting()); 999 if (isPainting()) 1000 return; 1001 1002 // Store the current maximal outline size to use when computing the old/new 1003 // outline rects for repainting. 1004 renderView()->setOldMaximalOutlineSize(renderView()->maximalOutlineSize()); 1005 1006 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get()); 1007 1008 if (!allowSubtree && m_layoutRoot) { 1009 m_layoutRoot->markContainingBlocksForLayout(false); 1010 m_layoutRoot = 0; 1011 } 1012 1013 performPreLayoutTasks(); 1014 1015 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 1016 // so there's no point to continuing to layout 1017 if (protector->hasOneRef()) 1018 return; 1019 1020 Document* document = m_frame->document(); 1021 bool inSubtreeLayout = m_layoutRoot; 1022 RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutRoot : document->renderer(); 1023 if (!rootForThisLayout) { 1024 // FIXME: Do we need to set m_size here? 1025 ASSERT_NOT_REACHED(); 1026 return; 1027 } 1028 1029 bool isPartialLayout = partialLayout().isPartialLayout(); 1030 1031 FontCachePurgePreventer fontCachePurgePreventer; 1032 RenderLayer* layer; 1033 { 1034 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false); 1035 1036 m_nestedLayoutCount++; 1037 if (!m_layoutRoot) { 1038 Document* document = m_frame->document(); 1039 Node* body = document->body(); 1040 if (body && body->renderer()) { 1041 if (body->hasTagName(framesetTag)) { 1042 body->renderer()->setChildNeedsLayout(); 1043 } else if (body->hasTagName(bodyTag)) { 1044 if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport()) 1045 body->renderer()->setChildNeedsLayout(); 1046 } 1047 } 1048 } 1049 updateCounters(); 1050 autoSizeIfEnabled(); 1051 1052 ScrollbarMode hMode; 1053 ScrollbarMode vMode; 1054 calculateScrollbarModesForLayout(hMode, vMode); 1055 1056 m_doFullRepaint = !inSubtreeLayout && !isPartialLayout && (m_firstLayout || toRenderView(rootForThisLayout)->document().printing()); 1057 1058 if (!inSubtreeLayout && !isPartialLayout) { 1059 // Now set our scrollbar state for the layout. 1060 ScrollbarMode currentHMode = horizontalScrollbarMode(); 1061 ScrollbarMode currentVMode = verticalScrollbarMode(); 1062 1063 if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) { 1064 if (m_firstLayout) { 1065 setScrollbarsSuppressed(true); 1066 1067 m_firstLayout = false; 1068 m_firstLayoutCallbackPending = true; 1069 m_lastViewportSize = layoutSize(IncludeScrollbars); 1070 m_lastZoomFactor = rootForThisLayout->style()->zoom(); 1071 1072 // Set the initial vMode to AlwaysOn if we're auto. 1073 if (vMode == ScrollbarAuto) 1074 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear. 1075 // Set the initial hMode to AlwaysOff if we're auto. 1076 if (hMode == ScrollbarAuto) 1077 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear. 1078 1079 setScrollbarModes(hMode, vMode); 1080 setScrollbarsSuppressed(false, true); 1081 } else 1082 setScrollbarModes(hMode, vMode); 1083 } 1084 1085 LayoutSize oldSize = m_size; 1086 1087 m_size = LayoutSize(layoutSize().width(), layoutSize().height()); 1088 1089 if (oldSize != m_size) { 1090 m_doFullRepaint = true; 1091 if (!m_firstLayout) { 1092 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0; 1093 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0; 1094 if (bodyRenderer && bodyRenderer->stretchesToViewport()) 1095 bodyRenderer->setChildNeedsLayout(); 1096 else if (rootRenderer && rootRenderer->stretchesToViewport()) 1097 rootRenderer->setChildNeedsLayout(); 1098 } 1099 } 1100 } 1101 1102 layer = rootForThisLayout->enclosingLayer(); 1103 1104 performLayout(rootForThisLayout, inSubtreeLayout); 1105 1106 m_layoutRoot = 0; 1107 } // Reset m_layoutSchedulingEnabled to its previous value. 1108 1109 bool neededFullRepaint = m_doFullRepaint; 1110 1111 if (!inSubtreeLayout && !isPartialLayout && !toRenderView(rootForThisLayout)->document().printing()) 1112 adjustViewSize(); 1113 1114 m_doFullRepaint = neededFullRepaint; 1115 1116 { 1117 // FIXME: Can this scope just encompass this entire function? 1118 FrameView::DeferredRepaintScope deferRepaints(*this); 1119 1120 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { 1121 if (m_doFullRepaint) 1122 renderView()->setShouldDoFullRepaintAfterLayout(true); 1123 1124 if (m_doFullRepaint || !partialLayout().isStopping()) 1125 repaintTree(rootForThisLayout); 1126 1127 } else if (m_doFullRepaint) { 1128 // FIXME: This isn't really right, since the RenderView doesn't fully encompass 1129 // the visibleContentRect(). It just happens to work out most of the time, 1130 // since first layouts and printing don't have you scrolled anywhere. 1131 renderView()->repaint(); 1132 } 1133 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, inSubtreeLayout, m_doFullRepaint)); 1134 } 1135 updateCompositingLayersAfterLayout(); 1136 1137 m_layoutCount++; 1138 1139 if (AXObjectCache* cache = rootForThisLayout->document().existingAXObjectCache()) 1140 cache->postNotification(rootForThisLayout, AXObjectCache::AXLayoutComplete, true); 1141 updateAnnotatedRegions(); 1142 1143 ASSERT(partialLayout().isStopping() || !rootForThisLayout->needsLayout()); 1144 1145 updateCanBlitOnScrollRecursively(); 1146 1147 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) 1148 updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight()); 1149 1150 scheduleOrPerformPostLayoutTasks(); 1151 1152 InspectorInstrumentation::didLayout(cookie, rootForThisLayout); 1153 1154 m_nestedLayoutCount--; 1155 if (m_nestedLayoutCount) 1156 return; 1157 1158 if (partialLayout().isStopping()) 1159 return; 1160 1161 #ifndef NDEBUG 1162 // Post-layout assert that nobody was re-marked as needing layout during layout. 1163 document->renderer()->assertSubtreeIsLaidOut(); 1164 #endif 1165 1166 // FIXME: It should be not possible to remove the FrameView from the frame/page during layout 1167 // however m_inLayout is not set for most of this function, so none of our RELEASE_ASSERTS 1168 // in Frame/Page will fire. One of the post-layout tasks is disconnecting the Frame from 1169 // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html 1170 // necessitating this check here. 1171 // ASSERT(frame()->page()); 1172 if (frame().page()) 1173 frame().page()->chrome().client().layoutUpdated(m_frame.get()); 1174 } 1175 1176 // The plan is to move to compositor-queried repainting, in which case this 1177 // method would setNeedsRedraw on the GraphicsLayers with invalidations and 1178 // let the compositor pick which to actually draw. 1179 // See http://crbug.com/306706 1180 void FrameView::repaintTree(RenderObject* root) 1181 { 1182 ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); 1183 ASSERT(!root->needsLayout()); 1184 1185 for (RenderObject* renderer = root; renderer; renderer = renderer->nextInPreOrder()) { 1186 const LayoutRect& oldRepaintRect = renderer->oldRepaintRect(); 1187 const LayoutRect& newRepaintRect = renderer->newRepaintRect(); 1188 1189 LayoutRect oldOutlineRect = oldRepaintRect; 1190 oldOutlineRect.inflate(renderView()->oldMaximalOutlineSize()); 1191 1192 LayoutRect newOutlineRect = newRepaintRect; 1193 newOutlineRect.inflate(renderView()->maximalOutlineSize()); 1194 1195 // FIXME: Currently renderers with layers will get repainted when we call updateLayerPositionsAfterLayout. 1196 // That call should be broken apart to position the layers be done before 1197 // the repaintTree call so this will repaint everything. 1198 bool didFullRepaint = false; 1199 if (!renderer->hasLayer()) { 1200 if (!renderer->layoutDidGetCalled()) { 1201 if (renderer->shouldDoFullRepaintAfterLayout()) { 1202 renderer->repaint(); 1203 didFullRepaint = true; 1204 } 1205 1206 } else { 1207 didFullRepaint = renderer->repaintAfterLayoutIfNeeded(renderer->containerForRepaint(), renderer->shouldDoFullRepaintAfterLayout(), 1208 oldRepaintRect, oldOutlineRect, &newRepaintRect, &newOutlineRect); 1209 } 1210 } 1211 if (!didFullRepaint && renderer->shouldRepaintOverflowIfNeeded()) 1212 renderer->repaintOverflow(); 1213 renderer->clearRepaintRects(); 1214 } 1215 renderView()->setOldMaximalOutlineSize(0); 1216 } 1217 1218 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot) 1219 { 1220 bool isTracing; 1221 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing); 1222 if (!isTracing) 1223 return; 1224 if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping()) 1225 return; 1226 GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer(); 1227 if (!graphicsLayer) 1228 return; 1229 1230 GraphicsLayerDebugInfo* debugInfo = new GraphicsLayerDebugInfo(); 1231 for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) { 1232 if (renderer->layoutDidGetCalled()) { 1233 LayoutRect rect = renderer->newRepaintRect(); 1234 debugInfo->m_currentLayoutRects.append(rect); 1235 renderer->setLayoutDidGetCalled(false); 1236 } 1237 } 1238 1239 graphicsLayer->setDebugInfo(debugInfo); 1240 } 1241 1242 1243 RenderBox* FrameView::embeddedContentBox() const 1244 { 1245 RenderView* renderView = this->renderView(); 1246 if (!renderView) 1247 return 0; 1248 1249 RenderObject* firstChild = renderView->firstChild(); 1250 if (!firstChild || !firstChild->isBox()) 1251 return 0; 1252 1253 // Curently only embedded SVG documents participate in the size-negotiation logic. 1254 if (firstChild->isSVGRoot()) 1255 return toRenderBox(firstChild); 1256 1257 return 0; 1258 } 1259 1260 void FrameView::addWidgetToUpdate(RenderEmbeddedObject& object) 1261 { 1262 // Tell the DOM element that it needs a widget update. 1263 Node* node = object.node(); 1264 if (node->hasTagName(objectTag) || node->hasTagName(embedTag)) 1265 toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true); 1266 1267 m_widgetUpdateSet.add(&object); 1268 } 1269 1270 void FrameView::setMediaType(const AtomicString& mediaType) 1271 { 1272 ASSERT(m_frame->document()); 1273 m_frame->document()->mediaQueryAffectingValueChanged(); 1274 m_mediaType = mediaType; 1275 } 1276 1277 AtomicString FrameView::mediaType() const 1278 { 1279 // See if we have an override type. 1280 String overrideType; 1281 InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType); 1282 if (!overrideType.isNull()) 1283 return overrideType; 1284 return m_mediaType; 1285 } 1286 1287 void FrameView::adjustMediaTypeForPrinting(bool printing) 1288 { 1289 if (printing) { 1290 if (m_mediaTypeWhenNotPrinting.isNull()) 1291 m_mediaTypeWhenNotPrinting = mediaType(); 1292 setMediaType("print"); 1293 } else { 1294 if (!m_mediaTypeWhenNotPrinting.isNull()) 1295 setMediaType(m_mediaTypeWhenNotPrinting); 1296 m_mediaTypeWhenNotPrinting = nullAtom; 1297 } 1298 } 1299 1300 bool FrameView::useSlowRepaints(bool considerOverlap) const 1301 { 1302 bool mustBeSlow = m_slowRepaintObjectCount > 0; 1303 1304 if (contentsInCompositedLayer()) 1305 return mustBeSlow; 1306 1307 // The chromium compositor does not support scrolling a non-composited frame within a composited page through 1308 // the fast scrolling path, so force slow scrolling in that case. 1309 if (m_frame->ownerElement() && !hasCompositedContent() && m_frame->page() && m_frame->page()->mainFrame()->view()->hasCompositedContent()) 1310 return true; 1311 1312 bool isOverlapped = m_isOverlapped && considerOverlap; 1313 1314 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque) 1315 return true; 1316 1317 if (FrameView* parentView = parentFrameView()) 1318 return parentView->useSlowRepaints(considerOverlap); 1319 1320 return false; 1321 } 1322 1323 bool FrameView::useSlowRepaintsIfNotOverlapped() const 1324 { 1325 return useSlowRepaints(false); 1326 } 1327 1328 void FrameView::updateCanBlitOnScrollRecursively() 1329 { 1330 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 1331 if (FrameView* view = frame->view()) 1332 view->setCanBlitOnScroll(!view->useSlowRepaints()); 1333 } 1334 } 1335 1336 bool FrameView::contentsInCompositedLayer() const 1337 { 1338 RenderView* renderView = this->renderView(); 1339 if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) { 1340 GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer(); 1341 if (layer && layer->drawsContent()) 1342 return true; 1343 } 1344 1345 return false; 1346 } 1347 1348 void FrameView::setCannotBlitToWindow() 1349 { 1350 m_cannotBlitToWindow = true; 1351 updateCanBlitOnScrollRecursively(); 1352 } 1353 1354 void FrameView::addSlowRepaintObject() 1355 { 1356 if (!m_slowRepaintObjectCount++) { 1357 updateCanBlitOnScrollRecursively(); 1358 1359 if (Page* page = m_frame->page()) { 1360 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1361 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this); 1362 } 1363 } 1364 } 1365 1366 void FrameView::removeSlowRepaintObject() 1367 { 1368 ASSERT(m_slowRepaintObjectCount > 0); 1369 m_slowRepaintObjectCount--; 1370 if (!m_slowRepaintObjectCount) { 1371 updateCanBlitOnScrollRecursively(); 1372 1373 if (Page* page = m_frame->page()) { 1374 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1375 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this); 1376 } 1377 } 1378 } 1379 1380 void FrameView::addViewportConstrainedObject(RenderObject* object) 1381 { 1382 if (!m_viewportConstrainedObjects) 1383 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet); 1384 1385 if (!m_viewportConstrainedObjects->contains(object)) { 1386 m_viewportConstrainedObjects->add(object); 1387 1388 if (Page* page = m_frame->page()) { 1389 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1390 scrollingCoordinator->frameViewFixedObjectsDidChange(this); 1391 } 1392 } 1393 } 1394 1395 void FrameView::removeViewportConstrainedObject(RenderObject* object) 1396 { 1397 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) { 1398 m_viewportConstrainedObjects->remove(object); 1399 if (Page* page = m_frame->page()) { 1400 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1401 scrollingCoordinator->frameViewFixedObjectsDidChange(this); 1402 } 1403 1404 // FIXME: In addFixedObject() we only call this if there's a platform widget, 1405 // why isn't the same check being made here? 1406 updateCanBlitOnScrollRecursively(); 1407 } 1408 } 1409 1410 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const 1411 { 1412 LayoutRect viewportRect = visibleContentRect(); 1413 // Ignore overhang. No-op when not using rubber banding. 1414 viewportRect.setLocation(clampScrollPosition(scrollPosition())); 1415 return viewportRect; 1416 } 1417 1418 1419 IntSize FrameView::scrollOffsetForFixedPosition() const 1420 { 1421 return toIntSize(clampScrollPosition(scrollPosition())); 1422 } 1423 1424 IntPoint FrameView::lastKnownMousePosition() const 1425 { 1426 return m_frame->eventHandler().lastKnownMousePosition(); 1427 } 1428 1429 bool FrameView::shouldSetCursor() const 1430 { 1431 Page* page = frame().page(); 1432 return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive(); 1433 } 1434 1435 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) 1436 { 1437 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) { 1438 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect); 1439 return true; 1440 } 1441 1442 const bool isCompositedContentLayer = contentsInCompositedLayer(); 1443 1444 // Get the rects of the fixed objects visible in the rectToScroll 1445 Region regionToUpdate; 1446 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end(); 1447 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) { 1448 RenderObject* renderer = *it; 1449 if (!renderer->style()->hasViewportConstrainedPosition()) 1450 continue; 1451 1452 // Fixed items should always have layers. 1453 ASSERT(renderer->hasLayer()); 1454 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); 1455 1456 // Layers that paint into their ancestor or into a grouped backing will still need 1457 // to apply a repaint invalidation. If the layer paints into its own backing, then 1458 // it does not need repainting just to scroll. 1459 if (layer->compositingState() == PaintsIntoOwnBacking) 1460 continue; 1461 1462 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView 1463 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) { 1464 // Don't invalidate for invisible fixed layers. 1465 continue; 1466 } 1467 1468 if (layer->hasAncestorWithFilterOutsets()) { 1469 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot 1470 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page. 1471 return false; 1472 } 1473 1474 IntRect updateRect = pixelSnappedIntRect(layer->repainter().repaintRectIncludingNonCompositingDescendants()); 1475 1476 RenderLayer* enclosingCompositingLayer = layer->enclosingCompositingLayer(false); 1477 if (enclosingCompositingLayer && !enclosingCompositingLayer->renderer()->isRenderView()) { 1478 // If the fixed-position layer is contained by a composited layer that is not its containing block, 1479 // then we have to invlidate that enclosing layer, not the RenderView. 1480 updateRect.moveBy(scrollPosition()); 1481 IntRect previousRect = updateRect; 1482 previousRect.move(scrollDelta); 1483 updateRect.unite(previousRect); 1484 enclosingCompositingLayer->repainter().setBackingNeedsRepaintInRect(updateRect); 1485 } else { 1486 // Coalesce the repaints that will be issued to the renderView. 1487 updateRect = contentsToRootView(updateRect); 1488 if (!isCompositedContentLayer && clipsRepaints()) 1489 updateRect.intersect(rectToScroll); 1490 if (!updateRect.isEmpty()) 1491 regionToUpdate.unite(updateRect); 1492 } 1493 } 1494 1495 // 1) scroll 1496 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect); 1497 1498 // 2) update the area of fixed objects that has been invalidated 1499 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects(); 1500 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size(); 1501 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) { 1502 IntRect updateRect = subRectsToUpdate[i]; 1503 IntRect scrolledRect = updateRect; 1504 scrolledRect.move(scrollDelta); 1505 updateRect.unite(scrolledRect); 1506 if (isCompositedContentLayer) { 1507 updateRect = rootViewToContents(updateRect); 1508 ASSERT(renderView()); 1509 renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect); 1510 continue; 1511 } 1512 if (clipsRepaints()) 1513 updateRect.intersect(rectToScroll); 1514 hostWindow()->invalidateContentsAndRootView(updateRect); 1515 } 1516 1517 return true; 1518 } 1519 1520 void FrameView::scrollContentsSlowPath(const IntRect& updateRect) 1521 { 1522 if (contentsInCompositedLayer()) { 1523 IntRect updateRect = visibleContentRect(); 1524 ASSERT(renderView()); 1525 renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect); 1526 } 1527 if (RenderPart* frameRenderer = m_frame->ownerRenderer()) { 1528 if (isEnclosedInCompositingLayer()) { 1529 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), 1530 frameRenderer->borderTop() + frameRenderer->paddingTop(), 1531 visibleWidth(), visibleHeight()); 1532 frameRenderer->repaintRectangle(rect); 1533 return; 1534 } 1535 } 1536 1537 ScrollView::scrollContentsSlowPath(updateRect); 1538 } 1539 1540 // Note that this gets called at painting time. 1541 void FrameView::setIsOverlapped(bool isOverlapped) 1542 { 1543 if (isOverlapped == m_isOverlapped) 1544 return; 1545 1546 m_isOverlapped = isOverlapped; 1547 updateCanBlitOnScrollRecursively(); 1548 } 1549 1550 bool FrameView::isOverlappedIncludingAncestors() const 1551 { 1552 if (isOverlapped()) 1553 return true; 1554 1555 if (FrameView* parentView = parentFrameView()) { 1556 if (parentView->isOverlapped()) 1557 return true; 1558 } 1559 1560 return false; 1561 } 1562 1563 void FrameView::setContentIsOpaque(bool contentIsOpaque) 1564 { 1565 if (contentIsOpaque == m_contentIsOpaque) 1566 return; 1567 1568 m_contentIsOpaque = contentIsOpaque; 1569 updateCanBlitOnScrollRecursively(); 1570 } 1571 1572 void FrameView::restoreScrollbar() 1573 { 1574 setScrollbarsSuppressed(false); 1575 } 1576 1577 bool FrameView::scrollToFragment(const KURL& url) 1578 { 1579 // If our URL has no ref, then we have no place we need to jump to. 1580 // OTOH If CSS target was set previously, we want to set it to 0, recalc 1581 // and possibly repaint because :target pseudo class may have been 1582 // set (see bug 11321). 1583 if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget()) 1584 return false; 1585 1586 String fragmentIdentifier = url.fragmentIdentifier(); 1587 if (scrollToAnchor(fragmentIdentifier)) 1588 return true; 1589 1590 // Try again after decoding the ref, based on the document's encoding. 1591 if (m_frame->document()->encoding().isValid()) 1592 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding())); 1593 1594 return false; 1595 } 1596 1597 bool FrameView::scrollToAnchor(const String& name) 1598 { 1599 ASSERT(m_frame->document()); 1600 1601 if (!m_frame->document()->haveStylesheetsLoaded()) { 1602 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); 1603 return false; 1604 } 1605 1606 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); 1607 1608 Element* anchorNode = m_frame->document()->findAnchor(name); 1609 1610 // Setting to null will clear the current target. 1611 m_frame->document()->setCSSTarget(anchorNode); 1612 1613 if (m_frame->document()->isSVGDocument()) { 1614 if (SVGSVGElement* svg = toSVGDocument(m_frame->document())->rootElement()) { 1615 svg->setupInitialView(name, anchorNode); 1616 if (!anchorNode) 1617 return true; 1618 } 1619 } 1620 1621 // Implement the rule that "" and "top" both mean top of page as in other browsers. 1622 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) 1623 return false; 1624 1625 maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document()); 1626 1627 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation. 1628 if (anchorNode && anchorNode->isFocusable()) 1629 m_frame->document()->setFocusedElement(anchorNode); 1630 1631 return true; 1632 } 1633 1634 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) 1635 { 1636 m_maintainScrollPositionAnchor = anchorNode; 1637 if (!m_maintainScrollPositionAnchor) 1638 return; 1639 1640 // We need to update the layout before scrolling, otherwise we could 1641 // really mess things up if an anchor scroll comes at a bad moment. 1642 m_frame->document()->updateStyleIfNeeded(); 1643 // Only do a layout if changes have occurred that make it necessary. 1644 RenderView* renderView = this->renderView(); 1645 if (renderView && renderView->needsLayout()) 1646 layout(); 1647 else 1648 scrollToAnchor(); 1649 } 1650 1651 void FrameView::scrollElementToRect(Element* element, const IntRect& rect) 1652 { 1653 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1654 1655 LayoutRect bounds = element->boundingBox(); 1656 int centeringOffsetX = (rect.width() - bounds.width()) / 2; 1657 int centeringOffsetY = (rect.height() - bounds.height()) / 2; 1658 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y())); 1659 } 1660 1661 void FrameView::setScrollPosition(const IntPoint& scrollPoint) 1662 { 1663 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); 1664 m_maintainScrollPositionAnchor = 0; 1665 1666 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint); 1667 1668 if (newScrollPosition == scrollPosition()) 1669 return; 1670 1671 ScrollView::setScrollPosition(newScrollPosition); 1672 } 1673 1674 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint) 1675 { 1676 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint); 1677 1678 if (newScrollPosition == scrollPosition()) 1679 return; 1680 1681 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false); 1682 notifyScrollPositionChanged(newScrollPosition); 1683 } 1684 1685 void FrameView::setViewportConstrainedObjectsNeedLayout() 1686 { 1687 if (!hasViewportConstrainedObjects()) 1688 return; 1689 1690 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end(); 1691 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) { 1692 RenderObject* renderer = *it; 1693 renderer->setNeedsLayout(); 1694 } 1695 } 1696 1697 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const 1698 { 1699 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize; 1700 } 1701 1702 void FrameView::setLayoutSize(const IntSize& size) 1703 { 1704 ASSERT(!layoutSizeFixedToFrameSize()); 1705 1706 setLayoutSizeInternal(size); 1707 } 1708 1709 void FrameView::scrollPositionChanged() 1710 { 1711 setWasScrolledByUser(true); 1712 1713 Document* document = m_frame->document(); 1714 document->enqueueScrollEventForNode(document); 1715 1716 m_frame->eventHandler().dispatchFakeMouseMoveEventSoon(); 1717 1718 if (RenderView* renderView = document->renderView()) { 1719 if (renderView->usesCompositing()) 1720 renderView->compositor()->frameViewDidScroll(); 1721 } 1722 1723 if (m_frame->document() && m_frame->document()->renderer()) { 1724 ResourceLoadPriorityOptimizer modifier; 1725 m_frame->document()->renderer()->didScroll(modifier); 1726 } 1727 } 1728 1729 void FrameView::repaintFixedElementsAfterScrolling() 1730 { 1731 // For fixed position elements, update widget positions and compositing layers after scrolling, 1732 // but only if we're not inside of layout. 1733 if (!m_nestedLayoutCount && hasViewportConstrainedObjects()) { 1734 if (RenderView* renderView = this->renderView()) { 1735 renderView->updateWidgetPositions(); 1736 renderView->layer()->updateLayerPositionsAfterDocumentScroll(); 1737 } 1738 } 1739 } 1740 1741 void FrameView::updateFixedElementsAfterScrolling() 1742 { 1743 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { 1744 if (RenderView* renderView = this->renderView()) 1745 renderView->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); 1746 } 1747 } 1748 1749 bool FrameView::shouldRubberBandInDirection(ScrollDirection direction) const 1750 { 1751 Page* page = frame().page(); 1752 if (!page) 1753 return ScrollView::shouldRubberBandInDirection(direction); 1754 return page->chrome().client().shouldRubberBandInDirection(direction); 1755 } 1756 1757 bool FrameView::isRubberBandInProgress() const 1758 { 1759 if (scrollbarsSuppressed()) 1760 return false; 1761 1762 // If the main thread updates the scroll position for this FrameView, we should return 1763 // ScrollAnimator::isRubberBandInProgress(). 1764 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) 1765 return scrollAnimator->isRubberBandInProgress(); 1766 1767 return false; 1768 } 1769 1770 HostWindow* FrameView::hostWindow() const 1771 { 1772 Page* page = frame().page(); 1773 if (!page) 1774 return 0; 1775 return &page->chrome(); 1776 } 1777 1778 const unsigned cRepaintRectUnionThreshold = 25; 1779 1780 void FrameView::repaintContentRectangle(const IntRect& r) 1781 { 1782 ASSERT(!m_frame->ownerElement()); 1783 1784 if (m_isTrackingRepaints) { 1785 IntRect repaintRect = r; 1786 repaintRect.move(-scrollOffset()); 1787 m_trackedRepaintRects.append(repaintRect); 1788 } 1789 1790 double delay = m_deferringRepaints ? 0 : adjustedDeferredRepaintDelay(); 1791 if (m_deferringRepaints || m_deferredRepaintTimer.isActive() || delay) { 1792 IntRect paintRect = r; 1793 if (clipsRepaints() && !paintsEntireContents()) 1794 paintRect.intersect(visibleContentRect()); 1795 if (paintRect.isEmpty()) 1796 return; 1797 if (m_repaintCount == cRepaintRectUnionThreshold) { 1798 IntRect unionedRect; 1799 for (unsigned i = 0; i < cRepaintRectUnionThreshold; ++i) 1800 unionedRect.unite(pixelSnappedIntRect(m_repaintRects[i])); 1801 m_repaintRects.clear(); 1802 m_repaintRects.append(unionedRect); 1803 } 1804 if (m_repaintCount < cRepaintRectUnionThreshold) 1805 m_repaintRects.append(paintRect); 1806 else 1807 m_repaintRects[0].unite(paintRect); 1808 m_repaintCount++; 1809 1810 if (!m_deferringRepaints) 1811 startDeferredRepaintTimer(delay); 1812 1813 return; 1814 } 1815 1816 if (!shouldUpdate()) 1817 return; 1818 1819 ScrollView::repaintContentRectangle(r); 1820 } 1821 1822 void FrameView::contentsResized() 1823 { 1824 ScrollView::contentsResized(); 1825 setNeedsLayout(); 1826 } 1827 1828 void FrameView::scrollbarExistenceDidChange() 1829 { 1830 // We check to make sure the view is attached to a frame() as this method can 1831 // be triggered before the view is attached by Frame::createView(...) setting 1832 // various values such as setScrollBarModes(...) for example. An ASSERT is 1833 // triggered when a view is layout before being attached to a frame(). 1834 if (!frame().view()) 1835 return; 1836 1837 // Note that simply having overlay scrollbars is not sufficient to be 1838 // certain that scrollbars' presence does not impact layout. This should 1839 // also check if custom scrollbars (as reported by shouldUseCustomScrollbars) 1840 // are in use as well. 1841 // http://crbug.com/269692 1842 bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars(); 1843 1844 if (!useOverlayScrollbars && needsLayout()) 1845 layout(); 1846 1847 if (renderView() && renderView()->usesCompositing()) { 1848 renderView()->compositor()->frameViewScrollbarsExistenceDidChange(); 1849 1850 if (!useOverlayScrollbars) 1851 renderView()->compositor()->frameViewDidChangeSize(); 1852 } 1853 } 1854 1855 void FrameView::beginDeferredRepaints() 1856 { 1857 Page* page = m_frame->page(); 1858 ASSERT(page); 1859 1860 if (!isMainFrame()) { 1861 page->mainFrame()->view()->beginDeferredRepaints(); 1862 return; 1863 } 1864 1865 m_deferringRepaints++; 1866 } 1867 1868 void FrameView::endDeferredRepaints() 1869 { 1870 Page* page = m_frame->page(); 1871 ASSERT(page); 1872 1873 if (!isMainFrame()) { 1874 page->mainFrame()->view()->endDeferredRepaints(); 1875 return; 1876 } 1877 1878 ASSERT(m_deferringRepaints > 0); 1879 1880 if (--m_deferringRepaints) 1881 return; 1882 1883 if (m_deferredRepaintTimer.isActive()) 1884 return; 1885 1886 if (double delay = adjustedDeferredRepaintDelay()) { 1887 startDeferredRepaintTimer(delay); 1888 return; 1889 } 1890 1891 doDeferredRepaints(); 1892 } 1893 1894 void FrameView::startDeferredRepaintTimer(double delay) 1895 { 1896 if (m_deferredRepaintTimer.isActive()) 1897 return; 1898 1899 m_deferredRepaintTimer.startOneShot(delay); 1900 } 1901 1902 void FrameView::handleLoadCompleted() 1903 { 1904 // Once loading has completed, allow autoSize one last opportunity to 1905 // reduce the size of the frame. 1906 autoSizeIfEnabled(); 1907 if (shouldUseLoadTimeDeferredRepaintDelay()) 1908 return; 1909 m_deferredRepaintDelay = s_normalDeferredRepaintDelay; 1910 flushDeferredRepaints(); 1911 } 1912 1913 void FrameView::flushDeferredRepaints() 1914 { 1915 if (!m_deferredRepaintTimer.isActive()) 1916 return; 1917 m_deferredRepaintTimer.stop(); 1918 doDeferredRepaints(); 1919 } 1920 1921 void FrameView::doDeferredRepaints() 1922 { 1923 ASSERT(!m_deferringRepaints); 1924 if (!shouldUpdate()) { 1925 m_repaintRects.clear(); 1926 m_repaintCount = 0; 1927 return; 1928 } 1929 unsigned size = m_repaintRects.size(); 1930 for (unsigned i = 0; i < size; i++) { 1931 ScrollView::repaintContentRectangle(pixelSnappedIntRect(m_repaintRects[i])); 1932 } 1933 m_repaintRects.clear(); 1934 m_repaintCount = 0; 1935 1936 updateDeferredRepaintDelayAfterRepaint(); 1937 } 1938 1939 bool FrameView::shouldUseLoadTimeDeferredRepaintDelay() const 1940 { 1941 // Don't defer after the initial load of the page has been completed. 1942 if (m_frame->tree().top()->document()->loadEventFinished()) 1943 return false; 1944 Document* document = m_frame->document(); 1945 if (!document) 1946 return false; 1947 if (document->parsing()) 1948 return true; 1949 if (document->fetcher()->requestCount()) 1950 return true; 1951 return false; 1952 } 1953 1954 void FrameView::updateDeferredRepaintDelayAfterRepaint() 1955 { 1956 if (!shouldUseLoadTimeDeferredRepaintDelay()) { 1957 m_deferredRepaintDelay = s_normalDeferredRepaintDelay; 1958 return; 1959 } 1960 double incrementedRepaintDelay = m_deferredRepaintDelay + s_deferredRepaintDelayIncrementDuringLoading; 1961 m_deferredRepaintDelay = std::min(incrementedRepaintDelay, s_maxDeferredRepaintDelayDuringLoading); 1962 } 1963 1964 void FrameView::resetDeferredRepaintDelay() 1965 { 1966 m_deferredRepaintDelay = 0; 1967 if (m_deferredRepaintTimer.isActive()) { 1968 m_deferredRepaintTimer.stop(); 1969 if (!m_deferringRepaints) 1970 doDeferredRepaints(); 1971 } 1972 } 1973 1974 double FrameView::adjustedDeferredRepaintDelay() const 1975 { 1976 ASSERT(!m_deferringRepaints); 1977 if (!m_deferredRepaintDelay) 1978 return 0; 1979 double timeSinceLastPaint = currentTime() - m_lastPaintTime; 1980 return max(0., m_deferredRepaintDelay - timeSinceLastPaint); 1981 } 1982 1983 void FrameView::deferredRepaintTimerFired(Timer<FrameView>*) 1984 { 1985 doDeferredRepaints(); 1986 } 1987 1988 void FrameView::layoutTimerFired(Timer<FrameView>*) 1989 { 1990 layout(); 1991 } 1992 1993 void FrameView::scheduleRelayout() 1994 { 1995 ASSERT(m_frame->view() == this); 1996 1997 if (m_layoutRoot) { 1998 m_layoutRoot->markContainingBlocksForLayout(false); 1999 m_layoutRoot = 0; 2000 } 2001 if (!m_layoutSchedulingEnabled) 2002 return; 2003 if (!needsLayout()) 2004 return; 2005 if (!m_frame->document()->shouldScheduleLayout()) 2006 return; 2007 InspectorInstrumentation::didInvalidateLayout(m_frame.get()); 2008 2009 // When frame seamless is enabled, the contents of the frame could affect the layout of the parent frames. 2010 // Also invalidate parent frame starting from the owner element of this frame. 2011 if (m_frame->ownerRenderer() && m_frame->document()->shouldDisplaySeamlesslyWithParent()) 2012 m_frame->ownerRenderer()->setNeedsLayout(); 2013 2014 int delay = m_frame->document()->minimumLayoutDelay(); 2015 if (m_layoutTimer.isActive() && m_delayedLayout && !delay) 2016 unscheduleRelayout(); 2017 if (m_layoutTimer.isActive()) 2018 return; 2019 2020 m_delayedLayout = delay != 0; 2021 m_layoutTimer.startOneShot(delay * 0.001); 2022 } 2023 2024 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant) 2025 { 2026 for (RenderObject* r = descendant; r; r = r->container()) { 2027 if (r == ancestor) 2028 return true; 2029 } 2030 return false; 2031 } 2032 2033 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) 2034 { 2035 ASSERT(m_frame->view() == this); 2036 2037 RenderView* renderView = this->renderView(); 2038 if (renderView && renderView->needsLayout()) { 2039 if (relayoutRoot) 2040 relayoutRoot->markContainingBlocksForLayout(false); 2041 return; 2042 } 2043 2044 if (layoutPending() || !m_layoutSchedulingEnabled) { 2045 if (m_layoutRoot != relayoutRoot) { 2046 if (isObjectAncestorContainerOf(m_layoutRoot, relayoutRoot)) { 2047 // Keep the current root 2048 relayoutRoot->markContainingBlocksForLayout(false, m_layoutRoot); 2049 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); 2050 } else if (m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, m_layoutRoot)) { 2051 // Re-root at relayoutRoot 2052 m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot); 2053 m_layoutRoot = relayoutRoot; 2054 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); 2055 InspectorInstrumentation::didInvalidateLayout(m_frame.get()); 2056 } else { 2057 // Just do a full relayout 2058 if (m_layoutRoot) 2059 m_layoutRoot->markContainingBlocksForLayout(false); 2060 m_layoutRoot = 0; 2061 relayoutRoot->markContainingBlocksForLayout(false); 2062 InspectorInstrumentation::didInvalidateLayout(m_frame.get()); 2063 } 2064 } 2065 } else if (m_layoutSchedulingEnabled) { 2066 int delay = m_frame->document()->minimumLayoutDelay(); 2067 m_layoutRoot = relayoutRoot; 2068 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); 2069 InspectorInstrumentation::didInvalidateLayout(m_frame.get()); 2070 m_delayedLayout = delay != 0; 2071 m_layoutTimer.startOneShot(delay * 0.001); 2072 } 2073 } 2074 2075 bool FrameView::layoutPending() const 2076 { 2077 return m_layoutTimer.isActive(); 2078 } 2079 2080 bool FrameView::needsLayout() const 2081 { 2082 // This can return true in cases where the document does not have a body yet. 2083 // Document::shouldScheduleLayout takes care of preventing us from scheduling 2084 // layout in that case. 2085 2086 RenderView* renderView = this->renderView(); 2087 return layoutPending() 2088 || (renderView && renderView->needsLayout()) 2089 || m_layoutRoot; 2090 } 2091 2092 void FrameView::setNeedsLayout() 2093 { 2094 if (RenderView* renderView = this->renderView()) 2095 renderView->setNeedsLayout(); 2096 } 2097 2098 void FrameView::unscheduleRelayout() 2099 { 2100 if (!m_layoutTimer.isActive()) 2101 return; 2102 2103 m_layoutTimer.stop(); 2104 m_delayedLayout = false; 2105 } 2106 2107 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime) 2108 { 2109 for (RefPtr<Frame> frame = m_frame; frame; frame = frame->tree().traverseNext()) { 2110 frame->view()->serviceScrollAnimations(); 2111 if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) 2112 frame->animation().serviceAnimations(); 2113 2114 DocumentAnimations::serviceOnAnimationFrame(*frame->document(), monotonicAnimationStartTime); 2115 } 2116 2117 Vector<RefPtr<Document> > documents; 2118 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) 2119 documents.append(frame->document()); 2120 2121 for (size_t i = 0; i < documents.size(); ++i) 2122 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime); 2123 } 2124 2125 bool FrameView::isTransparent() const 2126 { 2127 return m_isTransparent; 2128 } 2129 2130 void FrameView::setTransparent(bool isTransparent) 2131 { 2132 m_isTransparent = isTransparent; 2133 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) 2134 renderView()->layer()->compositedLayerMapping()->updateContentsOpaque(); 2135 } 2136 2137 bool FrameView::hasOpaqueBackground() const 2138 { 2139 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha(); 2140 } 2141 2142 Color FrameView::baseBackgroundColor() const 2143 { 2144 return m_baseBackgroundColor; 2145 } 2146 2147 void FrameView::setBaseBackgroundColor(const Color& backgroundColor) 2148 { 2149 if (!backgroundColor.isValid()) 2150 m_baseBackgroundColor = Color::white; 2151 else 2152 m_baseBackgroundColor = backgroundColor; 2153 2154 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) { 2155 CompositedLayerMappingPtr compositedLayerMapping = renderView()->layer()->compositedLayerMapping(); 2156 compositedLayerMapping->updateContentsOpaque(); 2157 if (compositedLayerMapping->mainGraphicsLayer()) 2158 compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay(); 2159 } 2160 recalculateScrollbarOverlayStyle(); 2161 } 2162 2163 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent) 2164 { 2165 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 2166 if (FrameView* view = frame->view()) { 2167 view->setTransparent(transparent); 2168 view->setBaseBackgroundColor(backgroundColor); 2169 } 2170 } 2171 } 2172 2173 bool FrameView::shouldUpdateWhileOffscreen() const 2174 { 2175 return m_shouldUpdateWhileOffscreen; 2176 } 2177 2178 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen) 2179 { 2180 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen; 2181 } 2182 2183 bool FrameView::shouldUpdate() const 2184 { 2185 if (isOffscreen() && !shouldUpdateWhileOffscreen()) 2186 return false; 2187 return true; 2188 } 2189 2190 void FrameView::scrollToAnchor() 2191 { 2192 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor; 2193 if (!anchorNode) 2194 return; 2195 2196 if (!anchorNode->renderer()) 2197 return; 2198 2199 LayoutRect rect; 2200 if (anchorNode != m_frame->document()) 2201 rect = anchorNode->boundingBox(); 2202 2203 // Scroll nested layers and frames to reveal the anchor. 2204 // Align to the top and to the closest side (this matches other browsers). 2205 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); 2206 2207 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) 2208 cache->handleScrolledToAnchor(anchorNode.get()); 2209 2210 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor. 2211 m_maintainScrollPositionAnchor = anchorNode; 2212 } 2213 2214 bool FrameView::updateWidgets() 2215 { 2216 if (m_nestedLayoutCount > 1 || m_widgetUpdateSet.isEmpty()) 2217 return true; 2218 2219 // Need to swap because script will run inside the below loop and invalidate the iterator. 2220 EmbeddedObjectSet objects; 2221 objects.swap(m_widgetUpdateSet); 2222 2223 for (EmbeddedObjectSet::iterator it = objects.begin(); it != objects.end(); ++it) { 2224 RenderEmbeddedObject& object = **it; 2225 HTMLPlugInElement* element = toHTMLPlugInElement(object.node()); 2226 2227 // The object may have already been destroyed (thus node cleared), 2228 // but FrameView holds a manual ref, so it won't have been deleted. 2229 if (!element) 2230 continue; 2231 2232 // No need to update if it's already crashed or known to be missing. 2233 if (object.showsUnavailablePluginIndicator()) 2234 continue; 2235 2236 if (element->needsWidgetUpdate()) 2237 element->updateWidget(); 2238 object.updateWidgetPosition(); 2239 2240 // Prevent plugins from causing infinite updates of themselves. 2241 // FIXME: Do we really need to prevent this? 2242 m_widgetUpdateSet.remove(&object); 2243 } 2244 2245 return m_widgetUpdateSet.isEmpty(); 2246 } 2247 2248 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*) 2249 { 2250 RefPtr<FrameView> protect(this); 2251 m_updateWidgetsTimer.stop(); 2252 for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) { 2253 if (updateWidgets()) 2254 return; 2255 } 2256 } 2257 2258 void FrameView::flushAnyPendingPostLayoutTasks() 2259 { 2260 if (m_postLayoutTasksTimer.isActive()) 2261 performPostLayoutTasks(); 2262 if (m_updateWidgetsTimer.isActive()) 2263 updateWidgetsTimerFired(0); 2264 } 2265 2266 void FrameView::performPostLayoutTasks() 2267 { 2268 TRACE_EVENT0("webkit", "FrameView::performPostLayoutTasks"); 2269 RefPtr<FrameView> protect(this); 2270 2271 m_postLayoutTasksTimer.stop(); 2272 2273 m_frame->selection().setCaretRectNeedsUpdate(); 2274 m_frame->selection().updateAppearance(); 2275 2276 if (m_nestedLayoutCount <= 1) { 2277 if (m_firstLayoutCallbackPending) { 2278 m_firstLayoutCallbackPending = false; 2279 m_frame->loader().didFirstLayout(); 2280 } 2281 2282 // Ensure that we always send this eventually. 2283 if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad()) 2284 m_isVisuallyNonEmpty = true; 2285 2286 // If the layout was done with pending sheets, we are not in fact visually non-empty yet. 2287 if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) { 2288 m_firstVisuallyNonEmptyLayoutCallbackPending = false; 2289 // FIXME: This callback is probably not needed, but is currently used 2290 // by android for setting the background color. 2291 m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout(); 2292 } 2293 } 2294 2295 FontFaceSet::didLayout(m_frame->document()); 2296 2297 RenderView* renderView = this->renderView(); 2298 if (renderView) 2299 renderView->updateWidgetPositions(); 2300 2301 if (!m_updateWidgetsTimer.isActive()) 2302 m_updateWidgetsTimer.startOneShot(0); 2303 2304 if (Page* page = m_frame->page()) { 2305 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 2306 scrollingCoordinator->notifyLayoutUpdated(); 2307 } 2308 2309 scrollToAnchor(); 2310 2311 sendResizeEventIfNeeded(); 2312 } 2313 2314 void FrameView::sendResizeEventIfNeeded() 2315 { 2316 ASSERT(m_frame); 2317 2318 RenderView* renderView = this->renderView(); 2319 if (!renderView || renderView->document().printing()) 2320 return; 2321 2322 IntSize currentSize = layoutSize(IncludeScrollbars); 2323 float currentZoomFactor = renderView->style()->zoom(); 2324 2325 bool shouldSendResizeEvent = currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor; 2326 2327 m_lastViewportSize = currentSize; 2328 m_lastZoomFactor = currentZoomFactor; 2329 2330 if (!shouldSendResizeEvent) 2331 return; 2332 2333 m_frame->document()->enqueueResizeEvent(); 2334 2335 if (isMainFrame()) 2336 InspectorInstrumentation::didResizeMainFrame(m_frame->page()); 2337 } 2338 2339 void FrameView::postLayoutTimerFired(Timer<FrameView>*) 2340 { 2341 performPostLayoutTasks(); 2342 } 2343 2344 void FrameView::updateCounters() 2345 { 2346 RenderView* view = renderView(); 2347 if (!view->hasRenderCounters()) 2348 return; 2349 2350 for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) { 2351 if (!renderer->isCounter()) 2352 continue; 2353 2354 toRenderCounter(renderer)->updateCounter(); 2355 } 2356 } 2357 2358 void FrameView::autoSizeIfEnabled() 2359 { 2360 if (!m_shouldAutoSize) 2361 return; 2362 2363 if (m_inAutoSize) 2364 return; 2365 2366 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true); 2367 2368 Document* document = frame().document(); 2369 if (!document) 2370 return; 2371 2372 RenderView* documentView = document->renderView(); 2373 Element* documentElement = document->documentElement(); 2374 if (!documentView || !documentElement) 2375 return; 2376 2377 RenderBox* documentRenderBox = documentElement->renderBox(); 2378 if (!documentRenderBox) 2379 return; 2380 2381 // If this is the first time we run autosize, start from small height and 2382 // allow it to grow. 2383 if (!m_didRunAutosize) 2384 resize(frameRect().width(), m_minAutoSize.height()); 2385 2386 IntSize size = frameRect().size(); 2387 2388 // Do the resizing twice. The first time is basically a rough calculation using the preferred width 2389 // which may result in a height change during the second iteration. 2390 for (int i = 0; i < 2; i++) { 2391 // Update various sizes including contentsSize, scrollHeight, etc. 2392 document->updateLayoutIgnorePendingStylesheets(); 2393 int width = documentView->minPreferredLogicalWidth(); 2394 int height = documentRenderBox->scrollHeight(); 2395 IntSize newSize(width, height); 2396 2397 // Check to see if a scrollbar is needed for a given dimension and 2398 // if so, increase the other dimension to account for the scrollbar. 2399 // Since the dimensions are only for the view rectangle, once a 2400 // dimension exceeds the maximum, there is no need to increase it further. 2401 if (newSize.width() > m_maxAutoSize.width()) { 2402 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar(); 2403 if (!localHorizontalScrollbar) 2404 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar); 2405 if (!localHorizontalScrollbar->isOverlayScrollbar()) 2406 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height()); 2407 2408 // Don't bother checking for a vertical scrollbar because the width is at 2409 // already greater the maximum. 2410 } else if (newSize.height() > m_maxAutoSize.height()) { 2411 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar(); 2412 if (!localVerticalScrollbar) 2413 localVerticalScrollbar = createScrollbar(VerticalScrollbar); 2414 if (!localVerticalScrollbar->isOverlayScrollbar()) 2415 newSize.setWidth(newSize.width() + localVerticalScrollbar->width()); 2416 2417 // Don't bother checking for a horizontal scrollbar because the height is 2418 // already greater the maximum. 2419 } 2420 2421 // Ensure the size is at least the min bounds. 2422 newSize = newSize.expandedTo(m_minAutoSize); 2423 2424 // Bound the dimensions by the max bounds and determine what scrollbars to show. 2425 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff; 2426 if (newSize.width() > m_maxAutoSize.width()) { 2427 newSize.setWidth(m_maxAutoSize.width()); 2428 horizonalScrollbarMode = ScrollbarAlwaysOn; 2429 } 2430 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff; 2431 if (newSize.height() > m_maxAutoSize.height()) { 2432 newSize.setHeight(m_maxAutoSize.height()); 2433 verticalScrollbarMode = ScrollbarAlwaysOn; 2434 } 2435 2436 if (newSize == size) 2437 continue; 2438 2439 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states) 2440 // unless autoresize has just been turned on or the maximum size is smaller than the current size. 2441 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width() 2442 && !m_frame->document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width())) 2443 break; 2444 2445 resize(newSize.width(), newSize.height()); 2446 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example, 2447 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed). 2448 setVerticalScrollbarLock(false); 2449 setHorizontalScrollbarLock(false); 2450 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true); 2451 } 2452 m_didRunAutosize = true; 2453 } 2454 2455 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) 2456 { 2457 if (!m_viewportRenderer) 2458 return; 2459 2460 if (m_overflowStatusDirty) { 2461 m_horizontalOverflow = horizontalOverflow; 2462 m_verticalOverflow = verticalOverflow; 2463 m_overflowStatusDirty = false; 2464 return; 2465 } 2466 2467 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow); 2468 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow); 2469 2470 if (horizontalOverflowChanged || verticalOverflowChanged) { 2471 m_horizontalOverflow = horizontalOverflow; 2472 m_verticalOverflow = verticalOverflow; 2473 2474 RefPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow); 2475 event->setTarget(m_viewportRenderer->node()); 2476 m_frame->document()->enqueueAnimationFrameEvent(event.release()); 2477 } 2478 2479 } 2480 2481 const Pagination& FrameView::pagination() const 2482 { 2483 if (m_pagination != Pagination()) 2484 return m_pagination; 2485 2486 if (isMainFrame()) 2487 return m_frame->page()->pagination(); 2488 2489 return m_pagination; 2490 } 2491 2492 void FrameView::setPagination(const Pagination& pagination) 2493 { 2494 if (m_pagination == pagination) 2495 return; 2496 2497 m_pagination = pagination; 2498 2499 m_frame->document()->styleResolverChanged(RecalcStyleDeferred); 2500 } 2501 2502 IntRect FrameView::windowClipRect(bool clipToContents) const 2503 { 2504 ASSERT(m_frame->view() == this); 2505 2506 if (paintsEntireContents()) 2507 return IntRect(IntPoint(), contentsSize()); 2508 2509 // Set our clip rect to be our contents. 2510 IntRect clipRect = contentsToWindow(visibleContentRect(clipToContents ? ExcludeScrollbars : IncludeScrollbars)); 2511 if (!m_frame->ownerElement()) 2512 return clipRect; 2513 2514 // Take our owner element and get its clip rect. 2515 HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement(); 2516 FrameView* parentView = ownerElement->document().view(); 2517 if (parentView) 2518 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true)); 2519 return clipRect; 2520 } 2521 2522 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const 2523 { 2524 // The renderer can sometimes be null when style="display:none" interacts 2525 // with external content and plugins. 2526 if (!ownerElement->renderer()) 2527 return windowClipRect(); 2528 2529 // If we have no layer, just return our window clip rect. 2530 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer(); 2531 if (!enclosingLayer) 2532 return windowClipRect(); 2533 2534 // Apply the clip from the layer. 2535 IntRect clipRect; 2536 if (clipToLayerContents) 2537 clipRect = pixelSnappedIntRect(enclosingLayer->childrenClipRect()); 2538 else 2539 clipRect = pixelSnappedIntRect(enclosingLayer->selfClipRect()); 2540 clipRect = contentsToWindow(clipRect); 2541 return intersection(clipRect, windowClipRect()); 2542 } 2543 2544 bool FrameView::isActive() const 2545 { 2546 Page* page = frame().page(); 2547 return page && page->focusController().isActive(); 2548 } 2549 2550 void FrameView::scrollTo(const IntSize& newOffset) 2551 { 2552 LayoutSize offset = scrollOffset(); 2553 ScrollView::scrollTo(newOffset); 2554 if (offset != scrollOffset()) 2555 scrollPositionChanged(); 2556 frame().loader().client()->didChangeScrollOffset(); 2557 } 2558 2559 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) 2560 { 2561 // Add in our offset within the FrameView. 2562 IntRect dirtyRect = rect; 2563 dirtyRect.moveBy(scrollbar->location()); 2564 invalidateRect(dirtyRect); 2565 } 2566 2567 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const 2568 { 2569 tickmarks = frame().document()->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch); 2570 } 2571 2572 IntRect FrameView::windowResizerRect() const 2573 { 2574 Page* page = frame().page(); 2575 if (!page) 2576 return IntRect(); 2577 return page->chrome().windowResizerRect(); 2578 } 2579 2580 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor) 2581 { 2582 if (m_visibleContentScaleFactor == visibleContentScaleFactor) 2583 return; 2584 2585 m_visibleContentScaleFactor = visibleContentScaleFactor; 2586 updateScrollbars(scrollOffset()); 2587 } 2588 2589 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor) 2590 { 2591 m_inputEventsOffsetForEmulation = offset; 2592 m_inputEventsScaleFactorForEmulation = contentScaleFactor; 2593 } 2594 2595 IntSize FrameView::inputEventsOffsetForEmulation() const 2596 { 2597 return m_inputEventsOffsetForEmulation; 2598 } 2599 2600 float FrameView::inputEventsScaleFactor() const 2601 { 2602 return visibleContentScaleFactor() * m_inputEventsScaleFactorForEmulation; 2603 } 2604 2605 bool FrameView::scrollbarsCanBeActive() const 2606 { 2607 if (m_frame->view() != this) 2608 return false; 2609 2610 return !!m_frame->document(); 2611 } 2612 2613 ScrollableArea* FrameView::enclosingScrollableArea() const 2614 { 2615 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer. 2616 return 0; 2617 } 2618 2619 IntRect FrameView::scrollableAreaBoundingBox() const 2620 { 2621 RenderPart* ownerRenderer = frame().ownerRenderer(); 2622 if (!ownerRenderer) 2623 return frameRect(); 2624 2625 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox(); 2626 } 2627 2628 bool FrameView::isScrollable() 2629 { 2630 // Check for: 2631 // 1) If there an actual overflow. 2632 // 2) display:none or visibility:hidden set to self or inherited. 2633 // 3) overflow{-x,-y}: hidden; 2634 // 4) scrolling: no; 2635 2636 // Covers #1 2637 IntSize contentsSize = this->contentsSize(); 2638 IntSize visibleContentSize = visibleContentRect().size(); 2639 if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width())) 2640 return false; 2641 2642 // Covers #2. 2643 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); 2644 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting())) 2645 return false; 2646 2647 // Cover #3 and #4. 2648 ScrollbarMode horizontalMode; 2649 ScrollbarMode verticalMode; 2650 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly); 2651 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) 2652 return false; 2653 2654 return true; 2655 } 2656 2657 void FrameView::updateScrollableAreaSet() 2658 { 2659 // That ensures that only inner frames are cached. 2660 FrameView* parentFrameView = this->parentFrameView(); 2661 if (!parentFrameView) 2662 return; 2663 2664 if (!isScrollable()) { 2665 parentFrameView->removeScrollableArea(this); 2666 return; 2667 } 2668 2669 parentFrameView->addScrollableArea(this); 2670 } 2671 2672 bool FrameView::shouldSuspendScrollAnimations() const 2673 { 2674 return m_frame->loader().state() != FrameStateComplete; 2675 } 2676 2677 void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate) 2678 { 2679 if (!isMainFrame()) 2680 return; 2681 2682 if (forceUpdate) 2683 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate); 2684 } 2685 2686 void FrameView::setAnimatorsAreActive() 2687 { 2688 Page* page = m_frame->page(); 2689 if (!page) 2690 return; 2691 2692 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) 2693 scrollAnimator->setIsActive(); 2694 2695 if (!m_scrollableAreas) 2696 return; 2697 2698 for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) { 2699 ScrollableArea* scrollableArea = *it; 2700 2701 ASSERT(scrollableArea->scrollbarsCanBeActive()); 2702 scrollableArea->scrollAnimator()->setIsActive(); 2703 } 2704 } 2705 2706 void FrameView::notifyPageThatContentAreaWillPaint() const 2707 { 2708 Page* page = m_frame->page(); 2709 if (!page) 2710 return; 2711 2712 contentAreaWillPaint(); 2713 2714 if (!m_scrollableAreas) 2715 return; 2716 2717 for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) { 2718 ScrollableArea* scrollableArea = *it; 2719 2720 if (!scrollableArea->scrollbarsCanBeActive()) 2721 continue; 2722 2723 scrollableArea->contentAreaWillPaint(); 2724 } 2725 } 2726 2727 bool FrameView::scrollAnimatorEnabled() const 2728 { 2729 if (m_frame->settings()) 2730 return m_frame->settings()->scrollAnimatorEnabled(); 2731 return false; 2732 } 2733 2734 void FrameView::updateAnnotatedRegions() 2735 { 2736 Document* document = m_frame->document(); 2737 if (!document->hasAnnotatedRegions()) 2738 return; 2739 Vector<AnnotatedRegionValue> newRegions; 2740 document->renderBox()->collectAnnotatedRegions(newRegions); 2741 if (newRegions == document->annotatedRegions()) 2742 return; 2743 document->setAnnotatedRegions(newRegions); 2744 if (Page* page = m_frame->page()) 2745 page->chrome().client().annotatedRegionsChanged(); 2746 } 2747 2748 void FrameView::updateScrollCorner() 2749 { 2750 RefPtr<RenderStyle> cornerStyle; 2751 IntRect cornerRect = scrollCornerRect(); 2752 Document* doc = m_frame->document(); 2753 2754 if (doc && !cornerRect.isEmpty()) { 2755 // Try the <body> element first as a scroll corner source. 2756 if (Element* body = doc->body()) { 2757 if (RenderObject* renderer = body->renderer()) 2758 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); 2759 } 2760 2761 if (!cornerStyle) { 2762 // If the <body> didn't have a custom style, then the root element might. 2763 if (Element* docElement = doc->documentElement()) { 2764 if (RenderObject* renderer = docElement->renderer()) 2765 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); 2766 } 2767 } 2768 2769 if (!cornerStyle) { 2770 // If we have an owning ipage/Frame element, then it can set the custom scrollbar also. 2771 if (RenderPart* renderer = m_frame->ownerRenderer()) 2772 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); 2773 } 2774 } 2775 2776 if (cornerStyle) { 2777 if (!m_scrollCorner) 2778 m_scrollCorner = RenderScrollbarPart::createAnonymous(doc); 2779 m_scrollCorner->setStyle(cornerStyle.release()); 2780 invalidateScrollCorner(cornerRect); 2781 } else if (m_scrollCorner) { 2782 m_scrollCorner->destroy(); 2783 m_scrollCorner = 0; 2784 } 2785 2786 ScrollView::updateScrollCorner(); 2787 } 2788 2789 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) 2790 { 2791 if (context->updatingControlTints()) { 2792 updateScrollCorner(); 2793 return; 2794 } 2795 2796 if (m_scrollCorner) { 2797 bool needsBackgorund = isMainFrame(); 2798 if (needsBackgorund) 2799 context->fillRect(cornerRect, baseBackgroundColor()); 2800 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect); 2801 return; 2802 } 2803 2804 ScrollView::paintScrollCorner(context, cornerRect); 2805 } 2806 2807 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect) 2808 { 2809 bool needsBackgorund = bar->isCustomScrollbar() && isMainFrame(); 2810 if (needsBackgorund) { 2811 IntRect toFill = bar->frameRect(); 2812 toFill.intersect(rect); 2813 context->fillRect(toFill, baseBackgroundColor()); 2814 } 2815 2816 ScrollView::paintScrollbar(context, bar, rect); 2817 } 2818 2819 Color FrameView::documentBackgroundColor() const 2820 { 2821 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of 2822 // the document and the body against the base background color of the frame view. 2823 // Background images are unfortunately impractical to include. 2824 2825 // Return invalid Color objects whenever there is insufficient information. 2826 if (!frame().document()) 2827 return Color(); 2828 2829 Element* htmlElement = frame().document()->documentElement(); 2830 Element* bodyElement = frame().document()->body(); 2831 2832 // Start with invalid colors. 2833 Color htmlBackgroundColor; 2834 Color bodyBackgroundColor; 2835 if (htmlElement && htmlElement->renderer()) 2836 htmlBackgroundColor = htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor); 2837 if (bodyElement && bodyElement->renderer()) 2838 bodyBackgroundColor = bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor); 2839 2840 if (!bodyBackgroundColor.isValid()) { 2841 if (!htmlBackgroundColor.isValid()) 2842 return Color(); 2843 return baseBackgroundColor().blend(htmlBackgroundColor); 2844 } 2845 2846 if (!htmlBackgroundColor.isValid()) 2847 return baseBackgroundColor().blend(bodyBackgroundColor); 2848 2849 // We take the aggregate of the base background color 2850 // the <html> background color, and the <body> 2851 // background color to find the document color. The 2852 // addition of the base background color is not 2853 // technically part of the document background, but it 2854 // otherwise poses problems when the aggregate is not 2855 // fully opaque. 2856 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor); 2857 } 2858 2859 bool FrameView::hasCustomScrollbars() const 2860 { 2861 const HashSet<RefPtr<Widget> >* viewChildren = children(); 2862 HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end(); 2863 for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { 2864 Widget* widget = current->get(); 2865 if (widget->isFrameView()) { 2866 if (toFrameView(widget)->hasCustomScrollbars()) 2867 return true; 2868 } else if (widget->isScrollbar()) { 2869 Scrollbar* scrollbar = static_cast<Scrollbar*>(widget); 2870 if (scrollbar->isCustomScrollbar()) 2871 return true; 2872 } 2873 } 2874 2875 return false; 2876 } 2877 2878 FrameView* FrameView::parentFrameView() const 2879 { 2880 if (!parent()) 2881 return 0; 2882 2883 if (Frame* parentFrame = m_frame->tree().parent()) 2884 return parentFrame->view(); 2885 2886 return 0; 2887 } 2888 2889 void FrameView::updateControlTints() 2890 { 2891 // This is called when control tints are changed from aqua/graphite to clear and vice versa. 2892 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate. 2893 // This is only done if the theme supports control tinting. It's up to the theme and platform 2894 // to define when controls get the tint and to call this function when that changes. 2895 2896 // Optimize the common case where we bring a window to the front while it's still empty. 2897 if (m_frame->document()->url().isEmpty()) 2898 return; 2899 2900 if (RenderTheme::theme().supportsControlTints() || hasCustomScrollbars()) 2901 paintControlTints(); 2902 } 2903 2904 void FrameView::paintControlTints() 2905 { 2906 if (needsLayout()) 2907 layout(); 2908 // FIXME: The use of paint seems like overkill: crbug.com/236892 2909 GraphicsContext context(0); // NULL canvas to get a non-painting context. 2910 context.setUpdatingControlTints(true); 2911 paint(&context, frameRect()); 2912 } 2913 2914 bool FrameView::wasScrolledByUser() const 2915 { 2916 return m_wasScrolledByUser; 2917 } 2918 2919 void FrameView::setWasScrolledByUser(bool wasScrolledByUser) 2920 { 2921 if (m_inProgrammaticScroll) 2922 return; 2923 m_maintainScrollPositionAnchor = 0; 2924 m_wasScrolledByUser = wasScrolledByUser; 2925 } 2926 2927 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) 2928 { 2929 Document* document = m_frame->document(); 2930 2931 #ifndef NDEBUG 2932 bool fillWithRed; 2933 if (document->printing()) 2934 fillWithRed = false; // Printing, don't fill with red (can't remember why). 2935 else if (m_frame->ownerElement()) 2936 fillWithRed = false; // Subframe, don't fill with red. 2937 else if (isTransparent()) 2938 fillWithRed = false; // Transparent, don't fill with red. 2939 else if (m_paintBehavior & PaintBehaviorSelectionOnly) 2940 fillWithRed = false; // Selections are transparent, don't fill with red. 2941 else if (m_nodeToDraw) 2942 fillWithRed = false; // Element images are transparent, don't fill with red. 2943 else 2944 fillWithRed = true; 2945 2946 if (fillWithRed) 2947 p->fillRect(rect, Color(0xFF, 0, 0)); 2948 #endif 2949 2950 RenderView* renderView = this->renderView(); 2951 if (!renderView) { 2952 WTF_LOG_ERROR("called FrameView::paint with nil renderer"); 2953 return; 2954 } 2955 2956 ASSERT(!needsLayout()); 2957 if (needsLayout()) 2958 return; 2959 2960 InspectorInstrumentation::willPaint(renderView, 0); 2961 2962 bool isTopLevelPainter = !s_inPaintContents; 2963 s_inPaintContents = true; 2964 2965 FontCachePurgePreventer fontCachePurgePreventer; 2966 2967 PaintBehavior oldPaintBehavior = m_paintBehavior; 2968 2969 if (FrameView* parentView = parentFrameView()) { 2970 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers) 2971 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers; 2972 } 2973 2974 if (m_paintBehavior == PaintBehaviorNormal) 2975 document->markers()->invalidateRenderedRectsForMarkersInRect(rect); 2976 2977 if (document->printing()) 2978 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers; 2979 2980 ASSERT(!m_isPainting); 2981 m_isPainting = true; 2982 2983 // m_nodeToDraw is used to draw only one element (and its descendants) 2984 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; 2985 RenderLayer* rootLayer = renderView->layer(); 2986 2987 #ifndef NDEBUG 2988 renderView->assertSubtreeIsLaidOut(); 2989 RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(rootLayer->renderer()); 2990 #endif 2991 2992 RenderObject* enclosingLayerRenderer = eltRenderer->enclosingLayer() ? eltRenderer->enclosingLayer()->renderer() : eltRenderer; 2993 rootLayer->paint(p, rect, m_paintBehavior, enclosingLayerRenderer); 2994 2995 if (rootLayer->containsDirtyOverlayScrollbars()) 2996 rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, eltRenderer); 2997 2998 m_isPainting = false; 2999 3000 m_paintBehavior = oldPaintBehavior; 3001 m_lastPaintTime = currentTime(); 3002 3003 // Regions may have changed as a result of the visibility/z-index of element changing. 3004 if (document->annotatedRegionsDirty()) 3005 updateAnnotatedRegions(); 3006 3007 if (isTopLevelPainter) { 3008 // Everythin that happens after paintContents completions is considered 3009 // to be part of the next frame. 3010 s_currentFrameTimeStamp = currentTime(); 3011 s_inPaintContents = false; 3012 } 3013 3014 InspectorInstrumentation::didPaint(renderView, 0, p, rect); 3015 } 3016 3017 void FrameView::setPaintBehavior(PaintBehavior behavior) 3018 { 3019 m_paintBehavior = behavior; 3020 } 3021 3022 PaintBehavior FrameView::paintBehavior() const 3023 { 3024 return m_paintBehavior; 3025 } 3026 3027 bool FrameView::isPainting() const 3028 { 3029 return m_isPainting; 3030 } 3031 3032 void FrameView::setNodeToDraw(Node* node) 3033 { 3034 m_nodeToDraw = node; 3035 } 3036 3037 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect) 3038 { 3039 if (context->paintingDisabled()) 3040 return; 3041 3042 if (m_frame->document()->printing()) 3043 return; 3044 3045 if (isMainFrame()) { 3046 if (m_frame->page()->chrome().client().paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect)) 3047 return; 3048 } 3049 3050 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect); 3051 } 3052 3053 void FrameView::updateLayoutAndStyleIfNeededRecursive() 3054 { 3055 // We have to crawl our entire tree looking for any FrameViews that need 3056 // layout and make sure they are up to date. 3057 // Mac actually tests for intersection with the dirty region and tries not to 3058 // update layout for frames that are outside the dirty region. Not only does this seem 3059 // pointless (since those frames will have set a zero timer to layout anyway), but 3060 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty 3061 // region but then become included later by the second frame adding rects to the dirty region 3062 // when it lays out. 3063 3064 m_frame->document()->updateStyleIfNeeded(); 3065 3066 if (needsLayout()) 3067 layout(); 3068 3069 // Grab a copy of the children() set, as it may be mutated by the following updateLayoutAndStyleIfNeededRecursive 3070 // calls, as they can potentially re-enter a layout of the parent frame view, which may add/remove scrollbars 3071 // and thus mutates the children() set. 3072 Vector<RefPtr<FrameView> > frameViews; 3073 collectFrameViewChildren(this, frameViews); 3074 3075 const Vector<RefPtr<FrameView> >::iterator end = frameViews.end(); 3076 for (Vector<RefPtr<FrameView> >::iterator it = frameViews.begin(); it != end; ++it) 3077 (*it)->updateLayoutAndStyleIfNeededRecursive(); 3078 3079 // updateLayoutAndStyleIfNeededRecursive is called when we need to make sure style and layout are up-to-date before 3080 // painting, so we need to flush out any deferred repaints too. 3081 flushDeferredRepaints(); 3082 3083 // When seamless is on, child frame can mark parent frame dirty. In such case, child frame 3084 // needs to call layout on parent frame recursively. 3085 // This assert ensures that parent frames are clean, when child frames finished updating layout and style. 3086 ASSERT(!needsLayout()); 3087 } 3088 3089 void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize) 3090 { 3091 ASSERT(!enable || !minSize.isEmpty()); 3092 ASSERT(minSize.width() <= maxSize.width()); 3093 ASSERT(minSize.height() <= maxSize.height()); 3094 3095 if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize) 3096 return; 3097 3098 3099 m_shouldAutoSize = enable; 3100 m_minAutoSize = minSize; 3101 m_maxAutoSize = maxSize; 3102 m_didRunAutosize = false; 3103 3104 setLayoutSizeFixedToFrameSize(enable); 3105 setNeedsLayout(); 3106 scheduleRelayout(); 3107 if (m_shouldAutoSize) 3108 return; 3109 3110 // Since autosize mode forces the scrollbar mode, change them to being auto. 3111 setVerticalScrollbarLock(false); 3112 setHorizontalScrollbarLock(false); 3113 setScrollbarModes(ScrollbarAuto, ScrollbarAuto); 3114 } 3115 3116 void FrameView::forceLayout(bool allowSubtree) 3117 { 3118 layout(allowSubtree); 3119 } 3120 3121 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor, AdjustViewSizeOrNot shouldAdjustViewSize) 3122 { 3123 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see 3124 // the state of things before and after the layout 3125 if (RenderView* renderView = this->renderView()) { 3126 float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); 3127 float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); 3128 3129 LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); 3130 LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); 3131 renderView->setLogicalWidth(flooredPageLogicalWidth); 3132 renderView->setPageLogicalHeight(flooredPageLogicalHeight); 3133 renderView->setNeedsLayoutAndPrefWidthsRecalc(); 3134 forceLayout(); 3135 3136 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the 3137 // page width when shrunk, we will lay out at maximum shrink and clip extra content. 3138 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping 3139 // implementation should not do this! 3140 bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode(); 3141 const LayoutRect& documentRect = renderView->documentRect(); 3142 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height(); 3143 if (docLogicalWidth > pageLogicalWidth) { 3144 int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor); 3145 int expectedPageHeight = std::min<float>(documentRect.height(), pageSize.height() * maximumShrinkFactor); 3146 FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), FloatSize(expectedPageWidth, expectedPageHeight)); 3147 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height(); 3148 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width(); 3149 3150 flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); 3151 flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); 3152 renderView->setLogicalWidth(flooredPageLogicalWidth); 3153 renderView->setPageLogicalHeight(flooredPageLogicalHeight); 3154 renderView->setNeedsLayoutAndPrefWidthsRecalc(); 3155 forceLayout(); 3156 3157 const LayoutRect& updatedDocumentRect = renderView->documentRect(); 3158 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width(); 3159 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x(); 3160 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY(); 3161 LayoutUnit clippedLogicalLeft = 0; 3162 if (!renderView->style()->isLeftToRightDirection()) 3163 clippedLogicalLeft = docLogicalRight - pageLogicalWidth; 3164 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight); 3165 3166 if (!horizontalWritingMode) 3167 overflow = overflow.transposedRect(); 3168 renderView->clearLayoutOverflow(); 3169 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. 3170 } 3171 } 3172 3173 if (shouldAdjustViewSize) 3174 adjustViewSize(); 3175 } 3176 3177 IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const 3178 { 3179 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox())); 3180 3181 // Convert from page ("absolute") to FrameView coordinates. 3182 rect.moveBy(-scrollPosition()); 3183 3184 return rect; 3185 } 3186 3187 IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const 3188 { 3189 IntRect rect = viewRect; 3190 3191 // Convert from FrameView coords into page ("absolute") coordinates. 3192 rect.moveBy(scrollPosition()); 3193 3194 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just 3195 // move the rect for now. 3196 rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms))); 3197 return rect; 3198 } 3199 3200 IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const 3201 { 3202 IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms)); 3203 3204 // Convert from page ("absolute") to FrameView coordinates. 3205 point.moveBy(-scrollPosition()); 3206 return point; 3207 } 3208 3209 IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const 3210 { 3211 IntPoint point = viewPoint; 3212 3213 // Convert from FrameView coords into page ("absolute") coordinates. 3214 point += IntSize(scrollX(), scrollY()); 3215 3216 return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms)); 3217 } 3218 3219 IntRect FrameView::convertToContainingView(const IntRect& localRect) const 3220 { 3221 if (const ScrollView* parentScrollView = toScrollView(parent())) { 3222 if (parentScrollView->isFrameView()) { 3223 const FrameView* parentView = toFrameView(parentScrollView); 3224 // Get our renderer in the parent view 3225 RenderPart* renderer = m_frame->ownerRenderer(); 3226 if (!renderer) 3227 return localRect; 3228 3229 IntRect rect(localRect); 3230 // Add borders and padding?? 3231 rect.move(renderer->borderLeft() + renderer->paddingLeft(), 3232 renderer->borderTop() + renderer->paddingTop()); 3233 return parentView->convertFromRenderer(renderer, rect); 3234 } 3235 3236 return Widget::convertToContainingView(localRect); 3237 } 3238 3239 return localRect; 3240 } 3241 3242 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const 3243 { 3244 if (const ScrollView* parentScrollView = toScrollView(parent())) { 3245 if (parentScrollView->isFrameView()) { 3246 const FrameView* parentView = toFrameView(parentScrollView); 3247 3248 // Get our renderer in the parent view 3249 RenderPart* renderer = m_frame->ownerRenderer(); 3250 if (!renderer) 3251 return parentRect; 3252 3253 IntRect rect = parentView->convertToRenderer(renderer, parentRect); 3254 // Subtract borders and padding 3255 rect.move(-renderer->borderLeft() - renderer->paddingLeft(), 3256 -renderer->borderTop() - renderer->paddingTop()); 3257 return rect; 3258 } 3259 3260 return Widget::convertFromContainingView(parentRect); 3261 } 3262 3263 return parentRect; 3264 } 3265 3266 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const 3267 { 3268 if (const ScrollView* parentScrollView = toScrollView(parent())) { 3269 if (parentScrollView->isFrameView()) { 3270 const FrameView* parentView = toFrameView(parentScrollView); 3271 3272 // Get our renderer in the parent view 3273 RenderPart* renderer = m_frame->ownerRenderer(); 3274 if (!renderer) 3275 return localPoint; 3276 3277 IntPoint point(localPoint); 3278 3279 // Add borders and padding 3280 point.move(renderer->borderLeft() + renderer->paddingLeft(), 3281 renderer->borderTop() + renderer->paddingTop()); 3282 return parentView->convertFromRenderer(renderer, point); 3283 } 3284 3285 return Widget::convertToContainingView(localPoint); 3286 } 3287 3288 return localPoint; 3289 } 3290 3291 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const 3292 { 3293 if (const ScrollView* parentScrollView = toScrollView(parent())) { 3294 if (parentScrollView->isFrameView()) { 3295 const FrameView* parentView = toFrameView(parentScrollView); 3296 3297 // Get our renderer in the parent view 3298 RenderPart* renderer = m_frame->ownerRenderer(); 3299 if (!renderer) 3300 return parentPoint; 3301 3302 IntPoint point = parentView->convertToRenderer(renderer, parentPoint); 3303 // Subtract borders and padding 3304 point.move(-renderer->borderLeft() - renderer->paddingLeft(), 3305 -renderer->borderTop() - renderer->paddingTop()); 3306 return point; 3307 } 3308 3309 return Widget::convertFromContainingView(parentPoint); 3310 } 3311 3312 return parentPoint; 3313 } 3314 3315 // Normal delay 3316 void FrameView::setRepaintThrottlingDeferredRepaintDelay(double p) 3317 { 3318 s_normalDeferredRepaintDelay = p; 3319 } 3320 3321 // Negative value would mean that first few repaints happen without a delay 3322 void FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(double p) 3323 { 3324 s_initialDeferredRepaintDelayDuringLoading = p; 3325 } 3326 3327 // The delay grows on each repaint to this maximum value 3328 void FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(double p) 3329 { 3330 s_maxDeferredRepaintDelayDuringLoading = p; 3331 } 3332 3333 // On each repaint the delay increases by this amount 3334 void FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(double p) 3335 { 3336 s_deferredRepaintDelayIncrementDuringLoading = p; 3337 } 3338 3339 void FrameView::setTracksRepaints(bool trackRepaints) 3340 { 3341 if (trackRepaints == m_isTrackingRepaints) 3342 return; 3343 3344 for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) { 3345 if (RenderView* renderView = frame->contentRenderer()) 3346 renderView->compositor()->setTracksRepaints(trackRepaints); 3347 } 3348 3349 resetTrackedRepaints(); 3350 m_isTrackingRepaints = trackRepaints; 3351 } 3352 3353 void FrameView::resetTrackedRepaints() 3354 { 3355 m_trackedRepaintRects.clear(); 3356 if (RenderView* renderView = this->renderView()) 3357 renderView->compositor()->resetTrackedRepaintRects(); 3358 } 3359 3360 String FrameView::trackedRepaintRectsAsText() const 3361 { 3362 TextStream ts; 3363 if (!m_trackedRepaintRects.isEmpty()) { 3364 ts << "(repaint rects\n"; 3365 for (size_t i = 0; i < m_trackedRepaintRects.size(); ++i) 3366 ts << " (rect " << m_trackedRepaintRects[i].x() << " " << m_trackedRepaintRects[i].y() << " " << m_trackedRepaintRects[i].width() << " " << m_trackedRepaintRects[i].height() << ")\n"; 3367 ts << ")\n"; 3368 } 3369 return ts.release(); 3370 } 3371 3372 void FrameView::addResizerArea(RenderBox* resizerBox) 3373 { 3374 if (!m_resizerAreas) 3375 m_resizerAreas = adoptPtr(new ResizerAreaSet); 3376 m_resizerAreas->add(resizerBox); 3377 } 3378 3379 void FrameView::removeResizerArea(RenderBox* resizerBox) 3380 { 3381 if (!m_resizerAreas) 3382 return; 3383 3384 ResizerAreaSet::iterator it = m_resizerAreas->find(resizerBox); 3385 if (it != m_resizerAreas->end()) 3386 m_resizerAreas->remove(it); 3387 } 3388 3389 bool FrameView::addScrollableArea(ScrollableArea* scrollableArea) 3390 { 3391 ASSERT(scrollableArea); 3392 if (!m_scrollableAreas) 3393 m_scrollableAreas = adoptPtr(new ScrollableAreaSet); 3394 return m_scrollableAreas->add(scrollableArea).isNewEntry; 3395 } 3396 3397 bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea) 3398 { 3399 if (!m_scrollableAreas) 3400 return false; 3401 3402 ScrollableAreaSet::iterator it = m_scrollableAreas->find(scrollableArea); 3403 if (it == m_scrollableAreas->end()) 3404 return false; 3405 3406 m_scrollableAreas->remove(it); 3407 return true; 3408 } 3409 3410 bool FrameView::containsScrollableArea(const ScrollableArea* scrollableArea) const 3411 { 3412 ASSERT(scrollableArea); 3413 if (!m_scrollableAreas || !scrollableArea) 3414 return false; 3415 return m_scrollableAreas->contains(const_cast<ScrollableArea*>(scrollableArea)); 3416 } 3417 3418 void FrameView::removeChild(Widget* widget) 3419 { 3420 if (widget->isFrameView()) 3421 removeScrollableArea(toFrameView(widget)); 3422 3423 ScrollView::removeChild(widget); 3424 } 3425 3426 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) 3427 { 3428 // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views 3429 // should handle wheel events. 3430 #if !USE(RUBBER_BANDING) 3431 if (!isScrollable()) 3432 return false; 3433 #endif 3434 3435 // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled. 3436 if (!canHaveScrollbars()) 3437 return false; 3438 3439 return ScrollableArea::handleWheelEvent(wheelEvent); 3440 } 3441 3442 bool FrameView::isVerticalDocument() const 3443 { 3444 RenderView* renderView = this->renderView(); 3445 if (!renderView) 3446 return true; 3447 3448 return renderView->style()->isHorizontalWritingMode(); 3449 } 3450 3451 bool FrameView::isFlippedDocument() const 3452 { 3453 RenderView* renderView = this->renderView(); 3454 if (!renderView) 3455 return false; 3456 3457 return renderView->style()->isFlippedBlocksWritingMode(); 3458 } 3459 3460 AXObjectCache* FrameView::axObjectCache() const 3461 { 3462 if (frame().document()) 3463 return frame().document()->existingAXObjectCache(); 3464 return 0; 3465 } 3466 3467 void FrameView::setCursor(const Cursor& cursor) 3468 { 3469 Page* page = frame().page(); 3470 if (!page) 3471 return; 3472 page->chrome().setCursor(cursor); 3473 } 3474 3475 bool FrameView::isMainFrame() const 3476 { 3477 return m_frame->isMainFrame(); 3478 } 3479 3480 void FrameView::frameRectsChanged() 3481 { 3482 if (layoutSizeFixedToFrameSize()) 3483 setLayoutSizeInternal(frameRect().size()); 3484 3485 ScrollView::frameRectsChanged(); 3486 } 3487 3488 void FrameView::setLayoutSizeInternal(const IntSize& size) 3489 { 3490 if (m_layoutSize == size) 3491 return; 3492 3493 m_layoutSize = size; 3494 contentsResized(); 3495 } 3496 3497 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) 3498 { 3499 ScrollableArea::didAddScrollbar(scrollbar, orientation); 3500 if (AXObjectCache* cache = axObjectCache()) 3501 cache->handleScrollbarUpdate(this); 3502 } 3503 3504 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) 3505 { 3506 ScrollableArea::willRemoveScrollbar(scrollbar, orientation); 3507 if (AXObjectCache* cache = axObjectCache()) { 3508 cache->remove(scrollbar); 3509 cache->handleScrollbarUpdate(this); 3510 } 3511 } 3512 3513 } // namespace WebCore 3514