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 "core/HTMLNames.h" 31 #include "core/MediaTypeNames.h" 32 #include "core/accessibility/AXObjectCache.h" 33 #include "core/css/FontFaceSet.h" 34 #include "core/css/resolver/StyleResolver.h" 35 #include "core/dom/DocumentMarkerController.h" 36 #include "core/editing/FrameSelection.h" 37 #include "core/editing/RenderedPosition.h" 38 #include "core/events/OverflowEvent.h" 39 #include "core/fetch/ResourceFetcher.h" 40 #include "core/fetch/ResourceLoadPriorityOptimizer.h" 41 #include "core/frame/FrameHost.h" 42 #include "core/frame/LocalFrame.h" 43 #include "core/frame/Settings.h" 44 #include "core/html/HTMLFrameElement.h" 45 #include "core/html/HTMLPlugInElement.h" 46 #include "core/html/parser/TextResourceDecoder.h" 47 #include "core/inspector/InspectorInstrumentation.h" 48 #include "core/inspector/InspectorTraceEvents.h" 49 #include "core/loader/FrameLoader.h" 50 #include "core/loader/FrameLoaderClient.h" 51 #include "core/page/Chrome.h" 52 #include "core/page/ChromeClient.h" 53 #include "core/page/EventHandler.h" 54 #include "core/page/FocusController.h" 55 #include "core/page/FrameTree.h" 56 #include "core/page/Page.h" 57 #include "core/page/scrolling/ScrollingCoordinator.h" 58 #include "core/rendering/RenderCounter.h" 59 #include "core/rendering/RenderEmbeddedObject.h" 60 #include "core/rendering/RenderLayer.h" 61 #include "core/rendering/RenderListBox.h" 62 #include "core/rendering/RenderPart.h" 63 #include "core/rendering/RenderScrollbar.h" 64 #include "core/rendering/RenderScrollbarPart.h" 65 #include "core/rendering/RenderTheme.h" 66 #include "core/rendering/RenderView.h" 67 #include "core/rendering/RenderWidget.h" 68 #include "core/rendering/TextAutosizer.h" 69 #include "core/rendering/compositing/CompositedLayerMapping.h" 70 #include "core/rendering/compositing/CompositedSelectionBound.h" 71 #include "core/rendering/compositing/RenderLayerCompositor.h" 72 #include "core/rendering/style/RenderStyle.h" 73 #include "core/rendering/svg/RenderSVGRoot.h" 74 #include "core/svg/SVGDocumentExtensions.h" 75 #include "core/svg/SVGSVGElement.h" 76 #include "platform/RuntimeEnabledFeatures.h" 77 #include "platform/ScriptForbiddenScope.h" 78 #include "platform/TraceEvent.h" 79 #include "platform/fonts/FontCache.h" 80 #include "platform/geometry/FloatRect.h" 81 #include "platform/graphics/GraphicsContext.h" 82 #include "platform/graphics/GraphicsLayerDebugInfo.h" 83 #include "platform/scroll/ScrollAnimator.h" 84 #include "platform/scroll/ScrollbarTheme.h" 85 #include "platform/text/TextStream.h" 86 #include "wtf/CurrentTime.h" 87 #include "wtf/TemporaryChange.h" 88 89 namespace blink { 90 91 using namespace HTMLNames; 92 93 double FrameView::s_currentFrameTimeStamp = 0.0; 94 bool FrameView::s_inPaintContents = false; 95 96 // The maximum number of updateWidgets iterations that should be done before returning. 97 static const unsigned maxUpdateWidgetsIterations = 2; 98 static const double resourcePriorityUpdateDelayAfterScroll = 0.250; 99 100 FrameView::FrameView(LocalFrame* frame) 101 : m_frame(frame) 102 , m_canHaveScrollbars(true) 103 , m_slowRepaintObjectCount(0) 104 , m_hasPendingLayout(false) 105 , m_layoutSubtreeRoot(0) 106 , m_inSynchronousPostLayout(false) 107 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) 108 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired) 109 , m_isTransparent(false) 110 , m_baseBackgroundColor(Color::white) 111 , m_mediaType(MediaTypeNames::screen) 112 , m_overflowStatusDirty(true) 113 , m_viewportRenderer(0) 114 , m_wasScrolledByUser(false) 115 , m_inProgrammaticScroll(false) 116 , m_safeToPropagateScrollToParent(true) 117 , m_isTrackingPaintInvalidations(false) 118 , m_scrollCorner(nullptr) 119 , m_visibleContentScaleFactor(1) 120 , m_inputEventsScaleFactorForEmulation(1) 121 , m_layoutSizeFixedToFrameSize(true) 122 , m_didScrollTimer(this, &FrameView::didScrollTimerFired) 123 , m_needsUpdateWidgetPositions(false) 124 , m_topControlsViewportAdjustment(0) 125 { 126 ASSERT(m_frame); 127 init(); 128 129 if (!m_frame->isMainFrame()) 130 return; 131 132 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed); 133 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed); 134 } 135 136 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame) 137 { 138 RefPtr<FrameView> view = adoptRef(new FrameView(frame)); 139 view->show(); 140 return view.release(); 141 } 142 143 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize) 144 { 145 RefPtr<FrameView> view = adoptRef(new FrameView(frame)); 146 view->Widget::setFrameRect(IntRect(view->location(), initialSize)); 147 view->setLayoutSizeInternal(initialSize); 148 149 view->show(); 150 return view.release(); 151 } 152 153 FrameView::~FrameView() 154 { 155 if (m_postLayoutTasksTimer.isActive()) 156 m_postLayoutTasksTimer.stop(); 157 158 if (m_didScrollTimer.isActive()) 159 m_didScrollTimer.stop(); 160 161 removeFromAXObjectCache(); 162 163 // Custom scrollbars should already be destroyed at this point 164 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar()); 165 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar()); 166 167 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow. 168 setHasVerticalScrollbar(false); 169 170 ASSERT(!m_scrollCorner); 171 172 ASSERT(m_frame); 173 ASSERT(m_frame->view() != this || !m_frame->contentRenderer()); 174 // FIXME: Do we need to do something here for OOPI? 175 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); 176 if (ownerElement && ownerElement->ownedWidget() == this) 177 ownerElement->setWidget(nullptr); 178 } 179 180 void FrameView::reset() 181 { 182 m_hasPendingLayout = false; 183 m_layoutSubtreeRoot = 0; 184 m_doFullPaintInvalidation = false; 185 m_layoutSchedulingEnabled = true; 186 m_inPerformLayout = false; 187 m_canInvalidatePaintDuringPerformLayout = false; 188 m_inSynchronousPostLayout = false; 189 m_layoutCount = 0; 190 m_nestedLayoutCount = 0; 191 m_postLayoutTasksTimer.stop(); 192 m_updateWidgetsTimer.stop(); 193 m_firstLayout = true; 194 m_firstLayoutCallbackPending = false; 195 m_wasScrolledByUser = false; 196 m_safeToPropagateScrollToParent = true; 197 m_lastViewportSize = IntSize(); 198 m_lastZoomFactor = 1.0f; 199 m_isTrackingPaintInvalidations = false; 200 m_trackedPaintInvalidationRects.clear(); 201 m_lastPaintTime = 0; 202 m_paintBehavior = PaintBehaviorNormal; 203 m_isPainting = false; 204 m_visuallyNonEmptyCharacterCount = 0; 205 m_visuallyNonEmptyPixelCount = 0; 206 m_isVisuallyNonEmpty = false; 207 m_firstVisuallyNonEmptyLayoutCallbackPending = true; 208 m_maintainScrollPositionAnchor = nullptr; 209 m_viewportConstrainedObjects.clear(); 210 } 211 212 void FrameView::removeFromAXObjectCache() 213 { 214 if (AXObjectCache* cache = axObjectCache()) { 215 cache->remove(this); 216 cache->childrenChanged(m_frame->pagePopupOwner()); 217 } 218 } 219 220 void FrameView::init() 221 { 222 reset(); 223 224 m_size = LayoutSize(); 225 226 // Propagate the marginwidth/height and scrolling modes to the view. 227 // FIXME: Do we need to do this for OOPI? 228 Element* ownerElement = m_frame->deprecatedLocalOwner(); 229 if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) { 230 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement); 231 if (frameElt->scrollingMode() == ScrollbarAlwaysOff) 232 setCanHaveScrollbars(false); 233 } 234 } 235 236 void FrameView::prepareForDetach() 237 { 238 RELEASE_ASSERT(!isInPerformLayout()); 239 240 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) 241 scrollAnimator->cancelAnimations(); 242 cancelProgrammaticScrollAnimation(); 243 244 detachCustomScrollbars(); 245 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache 246 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later. 247 removeFromAXObjectCache(); 248 249 if (m_frame->page()) { 250 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) 251 scrollingCoordinator->willDestroyScrollableArea(this); 252 } 253 } 254 255 void FrameView::detachCustomScrollbars() 256 { 257 Scrollbar* horizontalBar = horizontalScrollbar(); 258 if (horizontalBar && horizontalBar->isCustomScrollbar()) 259 setHasHorizontalScrollbar(false); 260 261 Scrollbar* verticalBar = verticalScrollbar(); 262 if (verticalBar && verticalBar->isCustomScrollbar()) 263 setHasVerticalScrollbar(false); 264 265 if (m_scrollCorner) { 266 m_scrollCorner->destroy(); 267 m_scrollCorner = nullptr; 268 } 269 } 270 271 void FrameView::recalculateScrollbarOverlayStyle() 272 { 273 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle(); 274 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; 275 276 Color backgroundColor = documentBackgroundColor(); 277 // Reduce the background color from RGB to a lightness value 278 // and determine which scrollbar style to use based on a lightness 279 // heuristic. 280 double hue, saturation, lightness; 281 backgroundColor.getHSL(hue, saturation, lightness); 282 if (lightness <= .5) 283 overlayStyle = ScrollbarOverlayStyleLight; 284 285 if (oldOverlayStyle != overlayStyle) 286 setScrollbarOverlayStyle(overlayStyle); 287 } 288 289 void FrameView::clear() 290 { 291 reset(); 292 setScrollbarsSuppressed(true); 293 } 294 295 bool FrameView::didFirstLayout() const 296 { 297 return !m_firstLayout; 298 } 299 300 void FrameView::invalidateRect(const IntRect& rect) 301 { 302 // For querying RenderLayer::compositingState() when invalidating scrollbars. 303 // FIXME: do all scrollbar invalidations after layout of all frames is complete. It's currently not recursively true. 304 DisableCompositingQueryAsserts disabler; 305 if (!parent()) { 306 if (HostWindow* window = hostWindow()) 307 window->invalidateContentsAndRootView(rect); 308 return; 309 } 310 311 RenderPart* renderer = m_frame->ownerRenderer(); 312 if (!renderer) 313 return; 314 315 IntRect paintInvalidationRect = rect; 316 paintInvalidationRect.move(renderer->borderLeft() + renderer->paddingLeft(), 317 renderer->borderTop() + renderer->paddingTop()); 318 renderer->invalidatePaintRectangle(paintInvalidationRect); 319 } 320 321 void FrameView::setFrameRect(const IntRect& newRect) 322 { 323 IntRect oldRect = frameRect(); 324 if (newRect == oldRect) 325 return; 326 327 // Autosized font sizes depend on the width of the viewing area. 328 bool autosizerNeedsUpdating = false; 329 if (newRect.width() != oldRect.width() && m_frame->isMainFrame() && m_frame->settings()->textAutosizingEnabled()) 330 autosizerNeedsUpdating = true; 331 332 ScrollView::setFrameRect(newRect); 333 334 updateScrollableAreaSet(); 335 336 if (autosizerNeedsUpdating) { 337 // This needs to be after the call to ScrollView::setFrameRect, because it reads the new width. 338 if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer()) 339 textAutosizer->updatePageInfoInAllFrames(); 340 } 341 342 if (RenderView* renderView = this->renderView()) { 343 if (renderView->usesCompositing()) 344 renderView->compositor()->frameViewDidChangeSize(); 345 } 346 347 viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height()); 348 349 if (oldRect.size() != newRect.size() 350 && m_frame->isMainFrame() 351 && m_frame->settings()->pinchVirtualViewportEnabled()) 352 page()->frameHost().pinchViewport().mainFrameDidChangeSize(); 353 } 354 355 Page* FrameView::page() const 356 { 357 return frame().page(); 358 } 359 360 RenderView* FrameView::renderView() const 361 { 362 return frame().contentRenderer(); 363 } 364 365 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) 366 { 367 m_canHaveScrollbars = canHaveScrollbars; 368 ScrollView::setCanHaveScrollbars(canHaveScrollbars); 369 } 370 371 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame) 372 { 373 customScrollbarElement = 0; 374 customScrollbarFrame = 0; 375 376 if (Settings* settings = m_frame->settings()) { 377 if (!settings->allowCustomScrollbarInMainFrame() && m_frame->isMainFrame()) 378 return false; 379 } 380 381 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). 382 Document* doc = m_frame->document(); 383 384 // Try the <body> element first as a scrollbar source. 385 Element* body = doc ? doc->body() : 0; 386 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) { 387 customScrollbarElement = body; 388 return true; 389 } 390 391 // If the <body> didn't have a custom style, then the root element might. 392 Element* docElement = doc ? doc->documentElement() : 0; 393 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) { 394 customScrollbarElement = docElement; 395 return true; 396 } 397 398 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also. 399 RenderPart* frameRenderer = m_frame->ownerRenderer(); 400 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) { 401 customScrollbarFrame = m_frame.get(); 402 return true; 403 } 404 405 return false; 406 } 407 408 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) 409 { 410 Element* customScrollbarElement = 0; 411 LocalFrame* customScrollbarFrame = 0; 412 if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame)) 413 return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame); 414 415 // Nobody set a custom style, so we just use a native scrollbar. 416 return ScrollView::createScrollbar(orientation); 417 } 418 419 void FrameView::setContentsSize(const IntSize& size) 420 { 421 if (size == contentsSize()) 422 return; 423 424 ScrollView::setContentsSize(size); 425 ScrollView::contentsResized(); 426 427 Page* page = frame().page(); 428 if (!page) 429 return; 430 431 updateScrollableAreaSet(); 432 433 page->chrome().contentsSizeChanged(m_frame.get(), size); 434 } 435 436 IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const 437 { 438 IntPoint maxScrollExtent(contentsSize().width() - scrollOrigin().x(), contentsSize().height() - scrollOrigin().y()); 439 FloatSize scaledSize = unscaledVisibleContentSize(); 440 if (scale) 441 scaledSize.scale(1 / scale); 442 443 IntPoint clampedOffset = offset; 444 clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize)); 445 clampedOffset = clampedOffset.expandedTo(-scrollOrigin()); 446 447 return clampedOffset; 448 } 449 450 void FrameView::adjustViewSize() 451 { 452 RenderView* renderView = this->renderView(); 453 if (!renderView) 454 return; 455 456 ASSERT(m_frame->view() == this); 457 458 const IntRect rect = renderView->documentRect(); 459 const IntSize& size = rect.size(); 460 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize()); 461 462 setContentsSize(size); 463 } 464 465 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode) 466 { 467 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats 468 // overflow:hidden and overflow:scroll on <body> as applying to the document's 469 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should 470 // use the root element. 471 472 EOverflow overflowX = o->style()->overflowX(); 473 EOverflow overflowY = o->style()->overflowY(); 474 475 if (o->isSVGRoot()) { 476 // Don't allow overflow to affect <img> and css backgrounds 477 if (toRenderSVGRoot(o)->isEmbeddedThroughSVGImage()) 478 return; 479 480 // FIXME: evaluate if we can allow overflow for these cases too. 481 // Overflow is always hidden when stand-alone SVG documents are embedded. 482 if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) { 483 overflowX = OHIDDEN; 484 overflowY = OHIDDEN; 485 } 486 } 487 488 bool ignoreOverflowHidden = false; 489 if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame()) 490 ignoreOverflowHidden = true; 491 492 switch (overflowX) { 493 case OHIDDEN: 494 if (!ignoreOverflowHidden) 495 hMode = ScrollbarAlwaysOff; 496 break; 497 case OSCROLL: 498 hMode = ScrollbarAlwaysOn; 499 break; 500 case OAUTO: 501 hMode = ScrollbarAuto; 502 break; 503 default: 504 // Don't set it at all. 505 ; 506 } 507 508 switch (overflowY) { 509 case OHIDDEN: 510 if (!ignoreOverflowHidden) 511 vMode = ScrollbarAlwaysOff; 512 break; 513 case OSCROLL: 514 vMode = ScrollbarAlwaysOn; 515 break; 516 case OAUTO: 517 vMode = ScrollbarAuto; 518 break; 519 default: 520 // Don't set it at all. 521 ; 522 } 523 524 m_viewportRenderer = o; 525 } 526 527 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy) 528 { 529 m_viewportRenderer = 0; 530 531 // FIXME: How do we handle this for OOPI? 532 const HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner(); 533 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) { 534 hMode = ScrollbarAlwaysOff; 535 vMode = ScrollbarAlwaysOff; 536 return; 537 } 538 539 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { 540 hMode = ScrollbarAuto; 541 vMode = ScrollbarAuto; 542 } else { 543 hMode = ScrollbarAlwaysOff; 544 vMode = ScrollbarAlwaysOff; 545 } 546 547 if (!isSubtreeLayout()) { 548 Document* document = m_frame->document(); 549 Node* body = document->body(); 550 if (isHTMLFrameSetElement(body) && body->renderer()) { 551 vMode = ScrollbarAlwaysOff; 552 hMode = ScrollbarAlwaysOff; 553 } else if (Element* viewportElement = document->viewportDefiningElement()) { 554 if (RenderObject* viewportRenderer = viewportElement->renderer()) { 555 if (viewportRenderer->style()) 556 applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode); 557 } 558 } 559 } 560 } 561 562 void FrameView::updateAcceleratedCompositingSettings() 563 { 564 if (RenderView* renderView = this->renderView()) 565 renderView->compositor()->updateAcceleratedCompositingSettings(); 566 } 567 568 void FrameView::recalcOverflowAfterStyleChange() 569 { 570 RenderView* renderView = this->renderView(); 571 RELEASE_ASSERT(renderView); 572 if (!renderView->needsOverflowRecalcAfterStyleChange()) 573 return; 574 575 renderView->recalcOverflowAfterStyleChange(); 576 577 IntRect documentRect = renderView->documentRect(); 578 if (scrollOrigin() == -documentRect.location() && contentsSize() == documentRect.size()) 579 return; 580 581 if (needsLayout()) 582 return; 583 584 InUpdateScrollbarsScope inUpdateScrollbarsScope(this); 585 586 bool shouldHaveHorizontalScrollbar = false; 587 bool shouldHaveVerticalScrollbar = false; 588 computeScrollbarExistence(shouldHaveHorizontalScrollbar, shouldHaveVerticalScrollbar, documentRect.size()); 589 590 bool hasHorizontalScrollbar = horizontalScrollbar(); 591 bool hasVerticalScrollbar = verticalScrollbar(); 592 if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar 593 || hasVerticalScrollbar != shouldHaveVerticalScrollbar) { 594 setNeedsLayout(); 595 return; 596 } 597 598 adjustViewSize(); 599 updateScrollbarGeometry(); 600 } 601 602 bool FrameView::usesCompositedScrolling() const 603 { 604 RenderView* renderView = this->renderView(); 605 if (!renderView) 606 return false; 607 if (m_frame->settings() && m_frame->settings()->preferCompositingToLCDTextEnabled()) 608 return renderView->compositor()->inCompositingMode(); 609 return false; 610 } 611 612 GraphicsLayer* FrameView::layerForScrolling() const 613 { 614 RenderView* renderView = this->renderView(); 615 if (!renderView) 616 return 0; 617 return renderView->compositor()->scrollLayer(); 618 } 619 620 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const 621 { 622 RenderView* renderView = this->renderView(); 623 if (!renderView) 624 return 0; 625 return renderView->compositor()->layerForHorizontalScrollbar(); 626 } 627 628 GraphicsLayer* FrameView::layerForVerticalScrollbar() const 629 { 630 RenderView* renderView = this->renderView(); 631 if (!renderView) 632 return 0; 633 return renderView->compositor()->layerForVerticalScrollbar(); 634 } 635 636 GraphicsLayer* FrameView::layerForScrollCorner() const 637 { 638 RenderView* renderView = this->renderView(); 639 if (!renderView) 640 return 0; 641 return renderView->compositor()->layerForScrollCorner(); 642 } 643 644 bool FrameView::isEnclosedInCompositingLayer() const 645 { 646 // FIXME: It's a bug that compositing state isn't always up to date when this is called. crbug.com/366314 647 DisableCompositingQueryAsserts disabler; 648 649 RenderObject* frameOwnerRenderer = m_frame->ownerRenderer(); 650 return frameOwnerRenderer && frameOwnerRenderer->enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries(); 651 } 652 653 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const 654 { 655 return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot; 656 } 657 658 inline void FrameView::forceLayoutParentViewIfNeeded() 659 { 660 RenderPart* ownerRenderer = m_frame->ownerRenderer(); 661 if (!ownerRenderer || !ownerRenderer->frame()) 662 return; 663 664 RenderBox* contentBox = embeddedContentBox(); 665 if (!contentBox) 666 return; 667 668 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox); 669 if (svgRoot->everHadLayout() && !svgRoot->needsLayout()) 670 return; 671 672 // If the embedded SVG document appears the first time, the ownerRenderer has already finished 673 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced 674 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before 675 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its 676 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the 677 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying 678 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>). 679 RefPtr<FrameView> frameView = ownerRenderer->frame()->view(); 680 681 // Mark the owner renderer as needing layout. 682 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); 683 684 // Synchronously enter layout, to layout the view containing the host object/embed/iframe. 685 ASSERT(frameView); 686 frameView->layout(); 687 } 688 689 void FrameView::performPreLayoutTasks() 690 { 691 TRACE_EVENT0("blink", "FrameView::performPreLayoutTasks"); 692 lifecycle().advanceTo(DocumentLifecycle::InPreLayout); 693 694 // Don't schedule more layouts, we're in one. 695 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false); 696 697 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) { 698 // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now. 699 m_inSynchronousPostLayout = true; 700 performPostLayoutTasks(); 701 m_inSynchronousPostLayout = false; 702 } 703 704 Document* document = m_frame->document(); 705 if (wasViewportResized()) 706 document->notifyResizeForViewportUnits(); 707 708 // Viewport-dependent media queries may cause us to need completely different style information. 709 if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) { 710 document->styleResolverChanged(); 711 document->mediaQueryAffectingValueChanged(); 712 713 // FIXME: This instrumentation event is not strictly accurate since cached media query results 714 // do not persist across StyleResolver rebuilds. 715 InspectorInstrumentation::mediaQueryResultChanged(document); 716 } else { 717 document->evaluateMediaQueryList(); 718 } 719 720 document->updateRenderTreeIfNeeded(); 721 lifecycle().advanceTo(DocumentLifecycle::StyleClean); 722 } 723 724 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout) 725 { 726 TRACE_EVENT0("blink", "FrameView::performLayout"); 727 728 ScriptForbiddenScope forbidScript; 729 730 ASSERT(!isInPerformLayout()); 731 lifecycle().advanceTo(DocumentLifecycle::InPerformLayout); 732 733 TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true); 734 735 // performLayout is the actual guts of layout(). 736 // FIXME: The 300 other lines in layout() probably belong in other helper functions 737 // so that a single human could understand what layout() is actually doing. 738 739 LayoutState layoutState(*rootForThisLayout); 740 741 forceLayoutParentViewIfNeeded(); 742 743 // FIXME (crbug.com/256657): Do not do two layouts for text autosizing. 744 rootForThisLayout->layout(); 745 gatherDebugLayoutRects(rootForThisLayout); 746 747 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities(); 748 749 lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout); 750 } 751 752 void FrameView::scheduleOrPerformPostLayoutTasks() 753 { 754 if (m_postLayoutTasksTimer.isActive()) 755 return; 756 757 if (!m_inSynchronousPostLayout) { 758 m_inSynchronousPostLayout = true; 759 // Calls resumeScheduledEvents() 760 performPostLayoutTasks(); 761 m_inSynchronousPostLayout = false; 762 } 763 764 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) { 765 // If we need layout or are already in a synchronous call to postLayoutTasks(), 766 // defer widget updates and event dispatch until after we return. postLayoutTasks() 767 // can make us need to update again, and we can get stuck in a nasty cycle unless 768 // we call it through the timer here. 769 m_postLayoutTasksTimer.startOneShot(0, FROM_HERE); 770 if (needsLayout()) 771 layout(); 772 } 773 } 774 775 void FrameView::layout(bool allowSubtree) 776 { 777 // We should never layout a Document which is not in a LocalFrame. 778 ASSERT(m_frame); 779 ASSERT(m_frame->view() == this); 780 ASSERT(m_frame->page()); 781 782 ScriptForbiddenScope forbidScript; 783 784 if (isInPerformLayout() || !m_frame->document()->isActive()) 785 return; 786 787 TRACE_EVENT0("blink", "FrameView::layout"); 788 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout"); 789 790 // Protect the view from being deleted during layout (in recalcStyle) 791 RefPtr<FrameView> protector(this); 792 793 // Every scroll that happens during layout is programmatic. 794 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); 795 796 if (m_autoSizeInfo) 797 m_autoSizeInfo->autoSizeIfNeeded(); 798 799 m_hasPendingLayout = false; 800 DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean); 801 802 RELEASE_ASSERT(!isPainting()); 803 804 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "beginData", InspectorLayoutEvent::beginData(this)); 805 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 806 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 807 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get()); 808 809 if (!allowSubtree && isSubtreeLayout()) { 810 m_layoutSubtreeRoot->markContainingBlocksForLayout(false); 811 m_layoutSubtreeRoot = 0; 812 } 813 814 performPreLayoutTasks(); 815 816 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 817 // so there's no point to continuing to layout 818 if (protector->hasOneRef()) 819 return; 820 821 Document* document = m_frame->document(); 822 bool inSubtreeLayout = isSubtreeLayout(); 823 RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView(); 824 if (!rootForThisLayout) { 825 // FIXME: Do we need to set m_size here? 826 ASSERT_NOT_REACHED(); 827 return; 828 } 829 830 FontCachePurgePreventer fontCachePurgePreventer; 831 RenderLayer* layer; 832 { 833 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false); 834 835 m_nestedLayoutCount++; 836 if (!inSubtreeLayout) { 837 Document* document = m_frame->document(); 838 Node* body = document->body(); 839 if (body && body->renderer()) { 840 if (isHTMLFrameSetElement(*body)) { 841 body->renderer()->setChildNeedsLayout(); 842 } else if (isHTMLBodyElement(*body)) { 843 if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport()) 844 body->renderer()->setChildNeedsLayout(); 845 } 846 } 847 } 848 updateCounters(); 849 850 ScrollbarMode hMode; 851 ScrollbarMode vMode; 852 calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode); 853 854 if (!inSubtreeLayout) { 855 // Now set our scrollbar state for the layout. 856 ScrollbarMode currentHMode = horizontalScrollbarMode(); 857 ScrollbarMode currentVMode = verticalScrollbarMode(); 858 859 if (m_firstLayout) { 860 setScrollbarsSuppressed(true); 861 862 m_doFullPaintInvalidation = true; 863 m_firstLayout = false; 864 m_firstLayoutCallbackPending = true; 865 m_lastViewportSize = layoutSize(IncludeScrollbars); 866 m_lastZoomFactor = rootForThisLayout->style()->zoom(); 867 868 // Set the initial vMode to AlwaysOn if we're auto. 869 if (vMode == ScrollbarAuto) 870 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear. 871 // Set the initial hMode to AlwaysOff if we're auto. 872 if (hMode == ScrollbarAuto) 873 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear. 874 875 setScrollbarModes(hMode, vMode); 876 setScrollbarsSuppressed(false, true); 877 } else if (hMode != currentHMode || vMode != currentVMode) { 878 setScrollbarModes(hMode, vMode); 879 } 880 881 LayoutSize oldSize = m_size; 882 883 m_size = LayoutSize(layoutSize().width(), layoutSize().height()); 884 885 if (oldSize != m_size && !m_firstLayout) { 886 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0; 887 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0; 888 if (bodyRenderer && bodyRenderer->stretchesToViewport()) 889 bodyRenderer->setChildNeedsLayout(); 890 else if (rootRenderer && rootRenderer->stretchesToViewport()) 891 rootRenderer->setChildNeedsLayout(); 892 } 893 894 // We need to set m_doFullPaintInvalidation before triggering layout as RenderObject::checkForPaintInvalidation 895 // checks the boolean to disable local paint invalidations. 896 m_doFullPaintInvalidation |= renderView()->shouldDoFullPaintInvalidationForNextLayout(); 897 } 898 899 layer = rootForThisLayout->enclosingLayer(); 900 901 performLayout(rootForThisLayout, inSubtreeLayout); 902 903 m_layoutSubtreeRoot = 0; 904 // We need to ensure that we mark up all renderers up to the RenderView 905 // for paint invalidation. This simplifies our code as we just always 906 // do a full tree walk. 907 if (RenderObject* container = rootForThisLayout->container()) 908 container->setMayNeedPaintInvalidation(true); 909 } // Reset m_layoutSchedulingEnabled to its previous value. 910 911 if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing()) 912 adjustViewSize(); 913 914 layer->updateLayerPositionsAfterLayout(); 915 916 renderView()->compositor()->didLayout(); 917 918 m_layoutCount++; 919 920 if (AXObjectCache* cache = rootForThisLayout->document().axObjectCache()) { 921 const KURL& url = rootForThisLayout->document().url(); 922 if (url.isValid() && !url.isAboutBlankURL()) 923 cache->handleLayoutComplete(rootForThisLayout); 924 } 925 updateAnnotatedRegions(); 926 927 ASSERT(!rootForThisLayout->needsLayout()); 928 929 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) 930 updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight()); 931 932 scheduleOrPerformPostLayoutTasks(); 933 934 TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout)); 935 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 936 InspectorInstrumentation::didLayout(cookie, rootForThisLayout); 937 938 m_nestedLayoutCount--; 939 if (m_nestedLayoutCount) 940 return; 941 942 #if ENABLE(ASSERT) 943 // Post-layout assert that nobody was re-marked as needing layout during layout. 944 document->renderView()->assertSubtreeIsLaidOut(); 945 #endif 946 947 // FIXME: It should be not possible to remove the FrameView from the frame/page during layout 948 // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS 949 // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from 950 // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html 951 // necessitating this check here. 952 // ASSERT(frame()->page()); 953 if (frame().page()) 954 frame().page()->chrome().client().layoutUpdated(m_frame.get()); 955 } 956 957 // The plan is to move to compositor-queried paint invalidation, in which case this 958 // method would setNeedsRedraw on the GraphicsLayers with invalidations and 959 // let the compositor pick which to actually draw. 960 // See http://crbug.com/306706 961 void FrameView::invalidateTreeIfNeeded() 962 { 963 ASSERT(renderView()); 964 RenderView& rootForPaintInvalidation = *renderView(); 965 ASSERT(!rootForPaintInvalidation.needsLayout()); 966 967 TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation.debugName().ascii()); 968 969 PaintInvalidationState rootPaintInvalidationState(rootForPaintInvalidation); 970 971 if (m_doFullPaintInvalidation) 972 renderView()->compositor()->fullyInvalidatePaint(); 973 974 rootForPaintInvalidation.invalidateTreeIfNeeded(rootPaintInvalidationState); 975 976 // Invalidate the paint of the frameviews scrollbars if needed 977 if (hasVerticalBarDamage()) 978 invalidateRect(verticalBarDamage()); 979 if (hasHorizontalBarDamage()) 980 invalidateRect(horizontalBarDamage()); 981 resetScrollbarDamage(); 982 983 984 #ifndef NDEBUG 985 renderView()->assertSubtreeClearedPaintInvalidationState(); 986 #endif 987 988 if (m_frame->selection().isCaretBoundsDirty()) 989 m_frame->selection().invalidateCaretRect(); 990 } 991 992 DocumentLifecycle& FrameView::lifecycle() const 993 { 994 return m_frame->document()->lifecycle(); 995 } 996 997 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot) 998 { 999 bool isTracing; 1000 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing); 1001 if (!isTracing) 1002 return; 1003 if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping()) 1004 return; 1005 // For access to compositedLayerMapping(). 1006 DisableCompositingQueryAsserts disabler; 1007 GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer(); 1008 if (!graphicsLayer) 1009 return; 1010 1011 GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo(); 1012 1013 debugInfo.currentLayoutRects().clear(); 1014 for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) { 1015 if (renderer->layoutDidGetCalled()) { 1016 FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect())); 1017 LayoutRect rect = quad.enclosingBoundingBox(); 1018 debugInfo.currentLayoutRects().append(rect); 1019 renderer->setLayoutDidGetCalled(false); 1020 } 1021 } 1022 } 1023 1024 RenderBox* FrameView::embeddedContentBox() const 1025 { 1026 RenderView* renderView = this->renderView(); 1027 if (!renderView) 1028 return 0; 1029 1030 RenderObject* firstChild = renderView->firstChild(); 1031 if (!firstChild || !firstChild->isBox()) 1032 return 0; 1033 1034 // Curently only embedded SVG documents participate in the size-negotiation logic. 1035 if (firstChild->isSVGRoot()) 1036 return toRenderBox(firstChild); 1037 1038 return 0; 1039 } 1040 1041 1042 void FrameView::addWidget(RenderWidget* object) 1043 { 1044 m_widgets.add(object); 1045 } 1046 1047 void FrameView::removeWidget(RenderWidget* object) 1048 { 1049 m_widgets.remove(object); 1050 } 1051 1052 void FrameView::updateWidgetPositions() 1053 { 1054 WillBeHeapVector<RefPtrWillBeMember<RenderWidget> > widgets; 1055 copyToVector(m_widgets, widgets); 1056 1057 // Script or plugins could detach the frame so abort processing if that happens. 1058 1059 for (size_t i = 0; i < widgets.size() && renderView(); ++i) 1060 widgets[i]->updateWidgetPosition(); 1061 1062 for (size_t i = 0; i < widgets.size() && renderView(); ++i) 1063 widgets[i]->widgetPositionsUpdated(); 1064 } 1065 1066 void FrameView::addWidgetToUpdate(RenderEmbeddedObject& object) 1067 { 1068 ASSERT(isInPerformLayout()); 1069 // Tell the DOM element that it needs a widget update. 1070 Node* node = object.node(); 1071 ASSERT(node); 1072 if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node)) 1073 toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true); 1074 1075 m_widgetUpdateSet.add(&object); 1076 } 1077 1078 void FrameView::setMediaType(const AtomicString& mediaType) 1079 { 1080 ASSERT(m_frame->document()); 1081 m_frame->document()->mediaQueryAffectingValueChanged(); 1082 m_mediaType = mediaType; 1083 } 1084 1085 AtomicString FrameView::mediaType() const 1086 { 1087 // See if we have an override type. 1088 String overrideType; 1089 InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType); 1090 if (!overrideType.isNull()) 1091 return AtomicString(overrideType); 1092 return m_mediaType; 1093 } 1094 1095 void FrameView::adjustMediaTypeForPrinting(bool printing) 1096 { 1097 if (printing) { 1098 if (m_mediaTypeWhenNotPrinting.isNull()) 1099 m_mediaTypeWhenNotPrinting = mediaType(); 1100 setMediaType(MediaTypeNames::print); 1101 } else { 1102 if (!m_mediaTypeWhenNotPrinting.isNull()) 1103 setMediaType(m_mediaTypeWhenNotPrinting); 1104 m_mediaTypeWhenNotPrinting = nullAtom; 1105 } 1106 } 1107 1108 bool FrameView::contentsInCompositedLayer() const 1109 { 1110 RenderView* renderView = this->renderView(); 1111 if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) { 1112 GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer(); 1113 if (layer && layer->drawsContent()) 1114 return true; 1115 } 1116 1117 return false; 1118 } 1119 1120 void FrameView::addSlowRepaintObject() 1121 { 1122 if (!m_slowRepaintObjectCount++) { 1123 if (Page* page = m_frame->page()) { 1124 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1125 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this); 1126 } 1127 } 1128 } 1129 1130 void FrameView::removeSlowRepaintObject() 1131 { 1132 ASSERT(m_slowRepaintObjectCount > 0); 1133 m_slowRepaintObjectCount--; 1134 if (!m_slowRepaintObjectCount) { 1135 if (Page* page = m_frame->page()) { 1136 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1137 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this); 1138 } 1139 } 1140 } 1141 1142 void FrameView::addViewportConstrainedObject(RenderObject* object) 1143 { 1144 if (!m_viewportConstrainedObjects) 1145 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet); 1146 1147 if (!m_viewportConstrainedObjects->contains(object)) { 1148 m_viewportConstrainedObjects->add(object); 1149 1150 if (Page* page = m_frame->page()) { 1151 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1152 scrollingCoordinator->frameViewFixedObjectsDidChange(this); 1153 } 1154 } 1155 } 1156 1157 void FrameView::removeViewportConstrainedObject(RenderObject* object) 1158 { 1159 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) { 1160 m_viewportConstrainedObjects->remove(object); 1161 1162 if (Page* page = m_frame->page()) { 1163 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1164 scrollingCoordinator->frameViewFixedObjectsDidChange(this); 1165 } 1166 } 1167 } 1168 1169 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const 1170 { 1171 LayoutRect viewportRect = visibleContentRect(); 1172 // Ignore overhang. No-op when not using rubber banding. 1173 viewportRect.setLocation(clampScrollPosition(scrollPosition())); 1174 return viewportRect; 1175 } 1176 1177 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged) 1178 { 1179 if (!hasViewportConstrainedObjects()) 1180 return; 1181 1182 // If viewport is not enabled, frameRect change will cause layout size change and then layout. 1183 // Otherwise, viewport constrained objects need their layout flags set separately to ensure 1184 // they are positioned correctly. In the virtual-viewport pinch mode frame rect changes wont 1185 // necessarily cause a layout size change so only take this early-out if we're in old-style 1186 // pinch. 1187 if (m_frame->settings() 1188 && !m_frame->settings()->viewportEnabled() 1189 && !m_frame->settings()->pinchVirtualViewportEnabled()) 1190 return; 1191 1192 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end(); 1193 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) { 1194 RenderObject* renderer = *it; 1195 RenderStyle* style = renderer->style(); 1196 if (widthChanged) { 1197 if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto())) 1198 renderer->setNeedsPositionedMovementLayout(); 1199 else 1200 renderer->setNeedsLayoutAndFullPaintInvalidation(); 1201 } 1202 if (heightChanged) { 1203 if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto())) 1204 renderer->setNeedsPositionedMovementLayout(); 1205 else 1206 renderer->setNeedsLayoutAndFullPaintInvalidation(); 1207 } 1208 } 1209 } 1210 1211 IntSize FrameView::scrollOffsetForFixedPosition() const 1212 { 1213 return toIntSize(clampScrollPosition(scrollPosition())); 1214 } 1215 1216 IntPoint FrameView::lastKnownMousePosition() const 1217 { 1218 return m_frame->eventHandler().lastKnownMousePosition(); 1219 } 1220 1221 bool FrameView::shouldSetCursor() const 1222 { 1223 Page* page = frame().page(); 1224 return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive() && page->settings().deviceSupportsMouse(); 1225 } 1226 1227 void FrameView::scrollContentsIfNeededRecursive() 1228 { 1229 scrollContentsIfNeeded(); 1230 1231 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) { 1232 if (!child->isLocalFrame()) 1233 continue; 1234 if (FrameView* view = toLocalFrame(child)->view()) 1235 view->scrollContentsIfNeededRecursive(); 1236 } 1237 } 1238 1239 void FrameView::scrollContentsIfNeeded() 1240 { 1241 bool didScroll = !pendingScrollDelta().isZero(); 1242 ScrollView::scrollContentsIfNeeded(); 1243 if (didScroll) 1244 updateFixedElementPaintInvalidationRectsAfterScroll(); 1245 } 1246 1247 static LayoutRect paintInvalidationRectIncludingNonCompositingDescendants(const RenderLayer* layer) 1248 { 1249 LayoutRect paintInvalidationRect = layer->renderer()->previousPaintInvalidationRect(); 1250 1251 for (const RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) { 1252 // Don't include paint invalidation rects for composited child layers; they will paint themselves and have a different origin. 1253 if (child->compositingState() == PaintsIntoOwnBacking || child->compositingState() == PaintsIntoGroupedBacking) 1254 continue; 1255 1256 paintInvalidationRect.unite(paintInvalidationRectIncludingNonCompositingDescendants(child)); 1257 } 1258 return paintInvalidationRect; 1259 } 1260 1261 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta) 1262 { 1263 if (!contentsInCompositedLayer() || hasSlowRepaintObjects()) 1264 return false; 1265 1266 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) { 1267 InspectorInstrumentation::didScroll(page()); 1268 return true; 1269 } 1270 1271 Region regionToUpdate; 1272 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end(); 1273 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) { 1274 RenderObject* renderer = *it; 1275 ASSERT(renderer->style()->hasViewportConstrainedPosition()); 1276 ASSERT(renderer->hasLayer()); 1277 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); 1278 1279 CompositingState state = layer->compositingState(); 1280 if (state == PaintsIntoOwnBacking || state == PaintsIntoGroupedBacking) 1281 continue; 1282 1283 if (layer->subtreeIsInvisible()) 1284 continue; 1285 1286 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot 1287 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page. 1288 if (layer->hasAncestorWithFilterOutsets()) 1289 return false; 1290 1291 IntRect updateRect = pixelSnappedIntRect(paintInvalidationRectIncludingNonCompositingDescendants(layer)); 1292 1293 const RenderLayerModelObject* repaintContainer = layer->renderer()->containerForPaintInvalidation(); 1294 if (repaintContainer && !repaintContainer->isRenderView()) { 1295 // Invalidate the old and new locations of fixed position elements that are not drawn into the RenderView. 1296 updateRect.moveBy(scrollPosition()); 1297 IntRect previousRect = updateRect; 1298 previousRect.move(scrollDelta); 1299 // FIXME: Rather than uniting the rects, we should just issue both invalidations. 1300 updateRect.unite(previousRect); 1301 layer->renderer()->invalidatePaintUsingContainer(repaintContainer, updateRect, InvalidationScroll); 1302 } else { 1303 // Coalesce the paint invalidations that will be issued to the renderView. 1304 updateRect = contentsToRootView(updateRect); 1305 if (!updateRect.isEmpty()) 1306 regionToUpdate.unite(updateRect); 1307 } 1308 } 1309 1310 InspectorInstrumentation::didScroll(page()); 1311 1312 // Invalidate the old and new locations of fixed position elements that are drawn into the RenderView. 1313 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects(); 1314 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size(); 1315 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) { 1316 IntRect updateRect = subRectsToUpdate[i]; 1317 IntRect scrolledRect = updateRect; 1318 scrolledRect.move(-scrollDelta); 1319 updateRect.unite(scrolledRect); 1320 // FIXME: We should be able to issue these invalidations separately and before we actually scroll. 1321 renderView()->setBackingNeedsPaintInvalidationInRect(rootViewToContents(updateRect)); 1322 } 1323 1324 return true; 1325 } 1326 1327 void FrameView::scrollContentsSlowPath(const IntRect& updateRect) 1328 { 1329 if (contentsInCompositedLayer()) { 1330 IntRect updateRect = visibleContentRect(); 1331 ASSERT(renderView()); 1332 renderView()->invalidatePaintRectangle(updateRect); 1333 } 1334 if (RenderPart* frameRenderer = m_frame->ownerRenderer()) { 1335 if (isEnclosedInCompositingLayer()) { 1336 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), 1337 frameRenderer->borderTop() + frameRenderer->paddingTop(), 1338 visibleWidth(), visibleHeight()); 1339 frameRenderer->invalidatePaintRectangle(rect); 1340 return; 1341 } 1342 } 1343 1344 ScrollView::scrollContentsSlowPath(updateRect); 1345 } 1346 1347 void FrameView::restoreScrollbar() 1348 { 1349 setScrollbarsSuppressed(false); 1350 } 1351 1352 bool FrameView::scrollToFragment(const KURL& url) 1353 { 1354 // If our URL has no ref, then we have no place we need to jump to. 1355 // OTOH If CSS target was set previously, we want to set it to 0, recalc 1356 // and possibly paint invalidation because :target pseudo class may have been 1357 // set (see bug 11321). 1358 if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget()) 1359 return false; 1360 1361 String fragmentIdentifier = url.fragmentIdentifier(); 1362 if (scrollToAnchor(fragmentIdentifier)) 1363 return true; 1364 1365 // Try again after decoding the ref, based on the document's encoding. 1366 if (m_frame->document()->encoding().isValid()) 1367 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding())); 1368 1369 return false; 1370 } 1371 1372 bool FrameView::scrollToAnchor(const String& name) 1373 { 1374 ASSERT(m_frame->document()); 1375 1376 if (!m_frame->document()->isRenderingReady()) { 1377 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); 1378 return false; 1379 } 1380 1381 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); 1382 1383 Element* anchorNode = m_frame->document()->findAnchor(name); 1384 1385 // Setting to null will clear the current target. 1386 m_frame->document()->setCSSTarget(anchorNode); 1387 1388 if (m_frame->document()->isSVGDocument()) { 1389 if (SVGSVGElement* svg = SVGDocumentExtensions::rootElement(*m_frame->document())) { 1390 svg->setupInitialView(name, anchorNode); 1391 if (!anchorNode) 1392 return true; 1393 } 1394 } 1395 1396 // Implement the rule that "" and "top" both mean top of page as in other browsers. 1397 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) 1398 return false; 1399 1400 maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document()); 1401 1402 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation. 1403 // If anchorNode is not focusable, setFocusedElement() will still clear focus, which matches the behavior of other browsers. 1404 if (anchorNode) 1405 m_frame->document()->setFocusedElement(anchorNode); 1406 1407 return true; 1408 } 1409 1410 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) 1411 { 1412 m_maintainScrollPositionAnchor = anchorNode; 1413 if (!m_maintainScrollPositionAnchor) 1414 return; 1415 1416 // We need to update the layout before scrolling, otherwise we could 1417 // really mess things up if an anchor scroll comes at a bad moment. 1418 m_frame->document()->updateRenderTreeIfNeeded(); 1419 // Only do a layout if changes have occurred that make it necessary. 1420 RenderView* renderView = this->renderView(); 1421 if (renderView && renderView->needsLayout()) 1422 layout(); 1423 else 1424 scrollToAnchor(); 1425 } 1426 1427 void FrameView::scrollElementToRect(Element* element, const IntRect& rect) 1428 { 1429 // FIXME(http://crbug.com/371896) - This method shouldn't be manually doing 1430 // coordinate transformations to the PinchViewport. 1431 IntRect targetRect(rect); 1432 1433 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1434 1435 bool pinchVirtualViewportEnabled = m_frame->settings()->pinchVirtualViewportEnabled(); 1436 1437 if (pinchVirtualViewportEnabled) { 1438 PinchViewport& pinchViewport = m_frame->page()->frameHost().pinchViewport(); 1439 1440 IntSize pinchViewportSize = expandedIntSize(pinchViewport.visibleRect().size()); 1441 targetRect.moveBy(ceiledIntPoint(pinchViewport.visibleRect().location())); 1442 targetRect.setSize(pinchViewportSize.shrunkTo(targetRect.size())); 1443 } 1444 1445 LayoutRect bounds = element->boundingBox(); 1446 int centeringOffsetX = (targetRect.width() - bounds.width()) / 2; 1447 int centeringOffsetY = (targetRect.height() - bounds.height()) / 2; 1448 1449 IntPoint targetOffset( 1450 bounds.x() - centeringOffsetX - targetRect.x(), 1451 bounds.y() - centeringOffsetY - targetRect.y()); 1452 1453 setScrollPosition(targetOffset); 1454 1455 if (pinchVirtualViewportEnabled) { 1456 IntPoint remainder = IntPoint(targetOffset - scrollPosition()); 1457 m_frame->page()->frameHost().pinchViewport().move(remainder); 1458 } 1459 } 1460 1461 void FrameView::setScrollPosition(const IntPoint& scrollPoint, ScrollBehavior scrollBehavior) 1462 { 1463 cancelProgrammaticScrollAnimation(); 1464 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); 1465 m_maintainScrollPositionAnchor = nullptr; 1466 1467 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint); 1468 1469 if (newScrollPosition == scrollPosition()) 1470 return; 1471 1472 if (scrollBehavior == ScrollBehaviorAuto) { 1473 RenderObject* renderer = m_frame->document()->documentElement() ? m_frame->document()->documentElement()->renderer() : 0; 1474 if (renderer) 1475 scrollBehavior = renderer->style()->scrollBehavior(); 1476 else 1477 scrollBehavior = ScrollBehaviorInstant; 1478 } 1479 ScrollView::setScrollPosition(newScrollPosition, scrollBehavior); 1480 } 1481 1482 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint) 1483 { 1484 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint); 1485 1486 if (newScrollPosition == scrollPosition()) 1487 return; 1488 1489 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false); 1490 notifyScrollPositionChanged(newScrollPosition); 1491 } 1492 1493 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const 1494 { 1495 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize; 1496 } 1497 1498 void FrameView::setLayoutSize(const IntSize& size) 1499 { 1500 ASSERT(!layoutSizeFixedToFrameSize()); 1501 1502 setLayoutSizeInternal(size); 1503 } 1504 1505 void FrameView::scrollPositionChanged() 1506 { 1507 setWasScrolledByUser(true); 1508 1509 Document* document = m_frame->document(); 1510 document->enqueueScrollEventForNode(document); 1511 1512 m_frame->eventHandler().dispatchFakeMouseMoveEventSoon(); 1513 1514 if (RenderView* renderView = document->renderView()) { 1515 if (renderView->usesCompositing()) 1516 renderView->compositor()->frameViewDidScroll(); 1517 } 1518 1519 if (m_didScrollTimer.isActive()) 1520 m_didScrollTimer.stop(); 1521 m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE); 1522 1523 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) 1524 cache->handleScrollPositionChanged(this); 1525 1526 frame().loader().saveScrollState(); 1527 } 1528 1529 void FrameView::didScrollTimerFired(Timer<FrameView>*) 1530 { 1531 if (m_frame->document() && m_frame->document()->renderView()) { 1532 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities(); 1533 } 1534 } 1535 1536 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded() 1537 { 1538 // Nothing to do after scrolling if there are no fixed position elements. 1539 if (!hasViewportConstrainedObjects()) 1540 return; 1541 1542 RefPtr<FrameView> protect(this); 1543 1544 // If there fixed position elements, scrolling may cause compositing layers to change. 1545 // Update widget and layer positions after scrolling, but only if we're not inside of 1546 // layout. 1547 if (!m_nestedLayoutCount) { 1548 updateWidgetPositions(); 1549 if (RenderView* renderView = this->renderView()) 1550 renderView->layer()->setNeedsCompositingInputsUpdate(); 1551 } 1552 } 1553 1554 bool FrameView::computeCompositedSelectionBounds(LocalFrame& frame, CompositedSelectionBound& start, CompositedSelectionBound& end) 1555 { 1556 const VisibleSelection &selection = frame.selection().selection(); 1557 if (!selection.isCaretOrRange()) 1558 return false; 1559 1560 VisiblePosition visibleStart(selection.visibleStart()); 1561 VisiblePosition visibleEnd(selection.visibleEnd()); 1562 1563 RenderedPosition renderedStart(visibleStart); 1564 RenderedPosition renderedEnd(visibleEnd); 1565 1566 renderedStart.positionInGraphicsLayerBacking(start); 1567 if (!start.layer) 1568 return false; 1569 1570 renderedEnd.positionInGraphicsLayerBacking(end); 1571 if (!end.layer) 1572 return false; 1573 1574 if (selection.isCaret()) { 1575 start.type = end.type = CompositedSelectionBound::Caret; 1576 return true; 1577 } 1578 1579 TextDirection startDir = visibleStart.deepEquivalent().primaryDirection(); 1580 TextDirection endDir = visibleEnd.deepEquivalent().primaryDirection(); 1581 start.type = startDir == RTL ? CompositedSelectionBound::SelectionRight : CompositedSelectionBound::SelectionLeft; 1582 end.type = endDir == RTL ? CompositedSelectionBound::SelectionLeft : CompositedSelectionBound::SelectionRight; 1583 return true; 1584 } 1585 1586 static void computePaintInvalidationRectsIncludingNonCompositingDescendants(RenderLayer* layer) 1587 { 1588 // FIXME: boundsRectForPaintInvalidation() has to walk up the parent chain 1589 // for every layer to compute the rects. We should make this more efficient. 1590 // FIXME: it's wrong to call this when layout is not up-to-date, which we do. 1591 layer->renderer()->setPreviousPaintInvalidationRect(layer->renderer()->boundsRectForPaintInvalidation(layer->renderer()->containerForPaintInvalidation())); 1592 // FIXME: We are only updating the paint invalidation bounds but not 1593 // the positionFromPaintInvalidationContainer. This means that we may 1594 // forcing a full invaliation of the new position. Is this really correct? 1595 1596 for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) { 1597 if (child->compositingState() != PaintsIntoOwnBacking && child->compositingState() != PaintsIntoGroupedBacking) 1598 computePaintInvalidationRectsIncludingNonCompositingDescendants(child); 1599 } 1600 } 1601 1602 void FrameView::updateFixedElementPaintInvalidationRectsAfterScroll() 1603 { 1604 if (!hasViewportConstrainedObjects()) 1605 return; 1606 1607 // Update the paint invalidation rects for fixed elements after scrolling and invalidation to reflect 1608 // the new scroll position. 1609 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end(); 1610 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) { 1611 RenderObject* renderer = *it; 1612 // m_viewportConstrainedObjects should not contain non-viewport constrained objects. 1613 ASSERT(renderer->style()->hasViewportConstrainedPosition()); 1614 1615 // Fixed items should always have layers. 1616 ASSERT(renderer->hasLayer()); 1617 1618 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); 1619 1620 // Don't need to do this for composited fixed items. 1621 if (layer->compositingState() == PaintsIntoOwnBacking) 1622 continue; 1623 1624 computePaintInvalidationRectsIncludingNonCompositingDescendants(layer); 1625 } 1626 } 1627 1628 void FrameView::updateCompositedSelectionBoundsIfNeeded() 1629 { 1630 if (!RuntimeEnabledFeatures::compositedSelectionUpdateEnabled()) 1631 return; 1632 1633 Page* page = frame().page(); 1634 ASSERT(page); 1635 1636 CompositedSelectionBound start, end; 1637 LocalFrame* frame = toLocalFrame(page->focusController().focusedOrMainFrame()); 1638 if (!frame || !computeCompositedSelectionBounds(*frame, start, end)) { 1639 page->chrome().client().clearCompositedSelectionBounds(); 1640 return; 1641 } 1642 1643 page->chrome().client().updateCompositedSelectionBounds(start, end); 1644 } 1645 1646 bool FrameView::isRubberBandInProgress() const 1647 { 1648 if (scrollbarsSuppressed()) 1649 return false; 1650 1651 // If the main thread updates the scroll position for this FrameView, we should return 1652 // ScrollAnimator::isRubberBandInProgress(). 1653 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) 1654 return scrollAnimator->isRubberBandInProgress(); 1655 1656 return false; 1657 } 1658 1659 HostWindow* FrameView::hostWindow() const 1660 { 1661 Page* page = frame().page(); 1662 if (!page) 1663 return 0; 1664 return &page->chrome(); 1665 } 1666 1667 void FrameView::contentRectangleForPaintInvalidation(const IntRect& r) 1668 { 1669 ASSERT(paintInvalidationIsAllowed()); 1670 ASSERT(!m_frame->ownerRenderer()); 1671 1672 if (m_isTrackingPaintInvalidations) { 1673 IntRect paintInvalidationRect = r; 1674 paintInvalidationRect.move(-scrollOffset()); 1675 m_trackedPaintInvalidationRects.append(paintInvalidationRect); 1676 // FIXME: http://crbug.com/368518. Eventually, invalidateContentRectangleForPaint 1677 // is going away entirely once all layout tests are FCM. In the short 1678 // term, no code should be tracking non-composited FrameView paint invalidations. 1679 RELEASE_ASSERT_NOT_REACHED(); 1680 } 1681 1682 ScrollView::contentRectangleForPaintInvalidation(r); 1683 } 1684 1685 void FrameView::contentsResized() 1686 { 1687 if (m_frame->isMainFrame() && m_frame->document()) { 1688 if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer()) 1689 textAutosizer->updatePageInfoInAllFrames(); 1690 } 1691 1692 ScrollView::contentsResized(); 1693 setNeedsLayout(); 1694 } 1695 1696 void FrameView::scrollbarExistenceDidChange() 1697 { 1698 // We check to make sure the view is attached to a frame() as this method can 1699 // be triggered before the view is attached by LocalFrame::createView(...) setting 1700 // various values such as setScrollBarModes(...) for example. An ASSERT is 1701 // triggered when a view is layout before being attached to a frame(). 1702 if (!frame().view()) 1703 return; 1704 1705 // Note that simply having overlay scrollbars is not sufficient to be 1706 // certain that scrollbars' presence does not impact layout. This should 1707 // also check if custom scrollbars (as reported by shouldUseCustomScrollbars) 1708 // are in use as well. 1709 // http://crbug.com/269692 1710 bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars(); 1711 1712 // FIXME: this call to layout() could be called within FrameView::layout(), but before performLayout(), 1713 // causing double-layout. See also crbug.com/429242. 1714 if (!useOverlayScrollbars && needsLayout()) 1715 layout(); 1716 1717 if (renderView() && renderView()->usesCompositing()) { 1718 renderView()->compositor()->frameViewScrollbarsExistenceDidChange(); 1719 1720 if (!useOverlayScrollbars) 1721 renderView()->compositor()->frameViewDidChangeSize(); 1722 } 1723 } 1724 1725 void FrameView::handleLoadCompleted() 1726 { 1727 // Once loading has completed, allow autoSize one last opportunity to 1728 // reduce the size of the frame. 1729 if (m_autoSizeInfo) 1730 m_autoSizeInfo->autoSizeIfNeeded(); 1731 } 1732 1733 void FrameView::scheduleRelayout() 1734 { 1735 ASSERT(m_frame->view() == this); 1736 1737 if (isSubtreeLayout()) { 1738 m_layoutSubtreeRoot->markContainingBlocksForLayout(false); 1739 m_layoutSubtreeRoot = 0; 1740 } 1741 if (!m_layoutSchedulingEnabled) 1742 return; 1743 if (!needsLayout()) 1744 return; 1745 if (!m_frame->document()->shouldScheduleLayout()) 1746 return; 1747 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get()); 1748 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 1749 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 1750 InspectorInstrumentation::didInvalidateLayout(m_frame.get()); 1751 1752 if (m_hasPendingLayout) 1753 return; 1754 m_hasPendingLayout = true; 1755 1756 page()->animator().scheduleVisualUpdate(); 1757 lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean); 1758 } 1759 1760 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant) 1761 { 1762 for (RenderObject* r = descendant; r; r = r->container()) { 1763 if (r == ancestor) 1764 return true; 1765 } 1766 return false; 1767 } 1768 1769 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) 1770 { 1771 ASSERT(m_frame->view() == this); 1772 1773 // FIXME: Should this call shouldScheduleLayout instead? 1774 if (!m_frame->document()->isActive()) 1775 return; 1776 1777 RenderView* renderView = this->renderView(); 1778 if (renderView && renderView->needsLayout()) { 1779 if (relayoutRoot) 1780 relayoutRoot->markContainingBlocksForLayout(false); 1781 return; 1782 } 1783 1784 if (layoutPending() || !m_layoutSchedulingEnabled) { 1785 if (m_layoutSubtreeRoot != relayoutRoot) { 1786 if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) { 1787 // Keep the current root 1788 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot); 1789 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout()); 1790 } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) { 1791 // Re-root at relayoutRoot 1792 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot); 1793 m_layoutSubtreeRoot = relayoutRoot; 1794 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout()); 1795 } else { 1796 // Just do a full relayout 1797 if (isSubtreeLayout()) 1798 m_layoutSubtreeRoot->markContainingBlocksForLayout(false); 1799 m_layoutSubtreeRoot = 0; 1800 relayoutRoot->markContainingBlocksForLayout(false); 1801 } 1802 } 1803 } else if (m_layoutSchedulingEnabled) { 1804 m_layoutSubtreeRoot = relayoutRoot; 1805 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout()); 1806 m_hasPendingLayout = true; 1807 1808 page()->animator().scheduleVisualUpdate(); 1809 lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean); 1810 } 1811 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get()); 1812 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 1813 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 1814 InspectorInstrumentation::didInvalidateLayout(m_frame.get()); 1815 } 1816 1817 bool FrameView::layoutPending() const 1818 { 1819 // FIXME: This should check Document::lifecycle instead. 1820 return m_hasPendingLayout; 1821 } 1822 1823 bool FrameView::isInPerformLayout() const 1824 { 1825 ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout)); 1826 return m_inPerformLayout; 1827 } 1828 1829 bool FrameView::needsLayout() const 1830 { 1831 // This can return true in cases where the document does not have a body yet. 1832 // Document::shouldScheduleLayout takes care of preventing us from scheduling 1833 // layout in that case. 1834 1835 RenderView* renderView = this->renderView(); 1836 return layoutPending() 1837 || (renderView && renderView->needsLayout()) 1838 || isSubtreeLayout(); 1839 } 1840 1841 void FrameView::setNeedsLayout() 1842 { 1843 if (RenderView* renderView = this->renderView()) 1844 renderView->setNeedsLayout(); 1845 } 1846 1847 bool FrameView::isTransparent() const 1848 { 1849 return m_isTransparent; 1850 } 1851 1852 void FrameView::setTransparent(bool isTransparent) 1853 { 1854 m_isTransparent = isTransparent; 1855 DisableCompositingQueryAsserts disabler; 1856 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) 1857 renderView()->layer()->compositedLayerMapping()->updateContentsOpaque(); 1858 } 1859 1860 bool FrameView::hasOpaqueBackground() const 1861 { 1862 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha(); 1863 } 1864 1865 Color FrameView::baseBackgroundColor() const 1866 { 1867 return m_baseBackgroundColor; 1868 } 1869 1870 void FrameView::setBaseBackgroundColor(const Color& backgroundColor) 1871 { 1872 m_baseBackgroundColor = backgroundColor; 1873 1874 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) { 1875 CompositedLayerMapping* compositedLayerMapping = renderView()->layer()->compositedLayerMapping(); 1876 compositedLayerMapping->updateContentsOpaque(); 1877 if (compositedLayerMapping->mainGraphicsLayer()) 1878 compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay(); 1879 } 1880 recalculateScrollbarOverlayStyle(); 1881 } 1882 1883 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent) 1884 { 1885 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 1886 if (!frame->isLocalFrame()) 1887 continue; 1888 if (FrameView* view = toLocalFrame(frame)->view()) { 1889 view->setTransparent(transparent); 1890 view->setBaseBackgroundColor(backgroundColor); 1891 } 1892 } 1893 } 1894 1895 void FrameView::scrollToAnchor() 1896 { 1897 RefPtrWillBeRawPtr<Node> anchorNode = m_maintainScrollPositionAnchor; 1898 if (!anchorNode) 1899 return; 1900 1901 if (!anchorNode->renderer()) 1902 return; 1903 1904 LayoutRect rect; 1905 if (anchorNode != m_frame->document()) 1906 rect = anchorNode->boundingBox(); 1907 1908 RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = m_frame->document()->findUnsafeParentScrollPropagationBoundary(); 1909 1910 if (boundaryFrame) 1911 boundaryFrame->view()->setSafeToPropagateScrollToParent(false); 1912 1913 // Scroll nested layers and frames to reveal the anchor. 1914 // Align to the top and to the closest side (this matches other browsers). 1915 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); 1916 1917 if (boundaryFrame) 1918 boundaryFrame->view()->setSafeToPropagateScrollToParent(true); 1919 1920 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) 1921 cache->handleScrolledToAnchor(anchorNode.get()); 1922 1923 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor. 1924 m_maintainScrollPositionAnchor = anchorNode; 1925 } 1926 1927 bool FrameView::updateWidgets() 1928 { 1929 // This is always called from updateWidgetsTimerFired. 1930 // m_updateWidgetsTimer should only be scheduled if we have widgets to update. 1931 // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty: 1932 ASSERT(!m_widgetUpdateSet.isEmpty()); 1933 if (m_nestedLayoutCount > 1 || m_widgetUpdateSet.isEmpty()) 1934 return true; 1935 1936 // Need to swap because script will run inside the below loop and invalidate the iterator. 1937 EmbeddedObjectSet objects; 1938 objects.swap(m_widgetUpdateSet); 1939 1940 for (EmbeddedObjectSet::iterator it = objects.begin(); it != objects.end(); ++it) { 1941 RenderEmbeddedObject& object = **it; 1942 HTMLPlugInElement* element = toHTMLPlugInElement(object.node()); 1943 1944 // The object may have already been destroyed (thus node cleared), 1945 // but FrameView holds a manual ref, so it won't have been deleted. 1946 if (!element) 1947 continue; 1948 1949 // No need to update if it's already crashed or known to be missing. 1950 if (object.showsUnavailablePluginIndicator()) 1951 continue; 1952 1953 if (element->needsWidgetUpdate()) 1954 element->updateWidget(); 1955 object.updateWidgetPosition(); 1956 1957 // Prevent plugins from causing infinite updates of themselves. 1958 // FIXME: Do we really need to prevent this? 1959 m_widgetUpdateSet.remove(&object); 1960 } 1961 1962 return m_widgetUpdateSet.isEmpty(); 1963 } 1964 1965 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*) 1966 { 1967 ASSERT(!isInPerformLayout()); 1968 RefPtr<FrameView> protect(this); 1969 m_updateWidgetsTimer.stop(); 1970 for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) { 1971 if (updateWidgets()) 1972 return; 1973 } 1974 } 1975 1976 void FrameView::flushAnyPendingPostLayoutTasks() 1977 { 1978 ASSERT(!isInPerformLayout()); 1979 if (m_postLayoutTasksTimer.isActive()) 1980 performPostLayoutTasks(); 1981 if (m_updateWidgetsTimer.isActive()) 1982 updateWidgetsTimerFired(0); 1983 } 1984 1985 void FrameView::scheduleUpdateWidgetsIfNecessary() 1986 { 1987 ASSERT(!isInPerformLayout()); 1988 if (m_updateWidgetsTimer.isActive() || m_widgetUpdateSet.isEmpty()) 1989 return; 1990 m_updateWidgetsTimer.startOneShot(0, FROM_HERE); 1991 } 1992 1993 void FrameView::performPostLayoutTasks() 1994 { 1995 // FIXME: We can reach here, even when the page is not active! 1996 // http/tests/inspector/elements/html-link-import.html and many other 1997 // tests hit that case. 1998 // We should ASSERT(isActive()); or at least return early if we can! 1999 ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call. 2000 TRACE_EVENT0("blink", "FrameView::performPostLayoutTasks"); 2001 RefPtr<FrameView> protect(this); 2002 2003 m_postLayoutTasksTimer.stop(); 2004 2005 m_frame->selection().setCaretRectNeedsUpdate(); 2006 2007 { 2008 // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html 2009 DisableCompositingQueryAsserts disabler; 2010 m_frame->selection().updateAppearance(); 2011 } 2012 2013 ASSERT(m_frame->document()); 2014 if (m_nestedLayoutCount <= 1) { 2015 if (m_firstLayoutCallbackPending) 2016 m_firstLayoutCallbackPending = false; 2017 2018 // Ensure that we always send this eventually. 2019 if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad()) 2020 m_isVisuallyNonEmpty = true; 2021 2022 // If the layout was done with pending sheets, we are not in fact visually non-empty yet. 2023 if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) { 2024 m_firstVisuallyNonEmptyLayoutCallbackPending = false; 2025 // FIXME: This callback is probably not needed, but is currently used 2026 // by android for setting the background color. 2027 m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout(); 2028 } 2029 } 2030 2031 FontFaceSet::didLayout(*m_frame->document()); 2032 2033 updateWidgetPositions(); 2034 2035 // Plugins could have torn down the page inside updateWidgetPositions(). 2036 if (!renderView()) 2037 return; 2038 2039 scheduleUpdateWidgetsIfNecessary(); 2040 2041 if (Page* page = m_frame->page()) { 2042 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 2043 scrollingCoordinator->notifyLayoutUpdated(); 2044 } 2045 2046 scrollToAnchor(); 2047 2048 sendResizeEventIfNeeded(); 2049 } 2050 2051 bool FrameView::wasViewportResized() 2052 { 2053 ASSERT(m_frame); 2054 RenderView* renderView = this->renderView(); 2055 if (!renderView) 2056 return false; 2057 return (layoutSize(IncludeScrollbars) != m_lastViewportSize || renderView->style()->zoom() != m_lastZoomFactor); 2058 } 2059 2060 void FrameView::sendResizeEventIfNeeded() 2061 { 2062 ASSERT(m_frame); 2063 2064 RenderView* renderView = this->renderView(); 2065 if (!renderView || renderView->document().printing()) 2066 return; 2067 2068 if (!wasViewportResized()) 2069 return; 2070 2071 m_lastViewportSize = layoutSize(IncludeScrollbars); 2072 m_lastZoomFactor = renderView->style()->zoom(); 2073 2074 m_frame->document()->enqueueResizeEvent(); 2075 2076 if (m_frame->isMainFrame()) 2077 InspectorInstrumentation::didResizeMainFrame(m_frame->page()); 2078 } 2079 2080 void FrameView::postLayoutTimerFired(Timer<FrameView>*) 2081 { 2082 performPostLayoutTasks(); 2083 } 2084 2085 void FrameView::updateCounters() 2086 { 2087 RenderView* view = renderView(); 2088 if (!view->hasRenderCounters()) 2089 return; 2090 2091 for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) { 2092 if (!renderer->isCounter()) 2093 continue; 2094 2095 toRenderCounter(renderer)->updateCounter(); 2096 } 2097 } 2098 2099 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) 2100 { 2101 if (!m_viewportRenderer) 2102 return; 2103 2104 if (m_overflowStatusDirty) { 2105 m_horizontalOverflow = horizontalOverflow; 2106 m_verticalOverflow = verticalOverflow; 2107 m_overflowStatusDirty = false; 2108 return; 2109 } 2110 2111 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow); 2112 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow); 2113 2114 if (horizontalOverflowChanged || verticalOverflowChanged) { 2115 m_horizontalOverflow = horizontalOverflow; 2116 m_verticalOverflow = verticalOverflow; 2117 2118 RefPtrWillBeRawPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow); 2119 event->setTarget(m_viewportRenderer->node()); 2120 m_frame->document()->enqueueAnimationFrameEvent(event.release()); 2121 } 2122 2123 } 2124 2125 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const 2126 { 2127 ASSERT(m_frame->view() == this); 2128 2129 // Set our clip rect to be our contents. 2130 IntRect clipRect = contentsToWindow(visibleContentRect(scrollbarInclusion)); 2131 if (!m_frame->deprecatedLocalOwner()) 2132 return clipRect; 2133 2134 // Take our owner element and get its clip rect. 2135 // FIXME: Do we need to do this for remote frames? 2136 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); 2137 FrameView* parentView = ownerElement->document().view(); 2138 if (parentView) 2139 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement)); 2140 return clipRect; 2141 } 2142 2143 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement) const 2144 { 2145 // The renderer can sometimes be null when style="display:none" interacts 2146 // with external content and plugins. 2147 if (!ownerElement->renderer()) 2148 return windowClipRect(); 2149 2150 // If we have no layer, just return our window clip rect. 2151 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer(); 2152 if (!enclosingLayer) 2153 return windowClipRect(); 2154 2155 // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date. 2156 // https://code.google.com/p/chromium/issues/detail?id=343769 2157 DisableCompositingQueryAsserts disabler; 2158 2159 // Apply the clip from the layer. 2160 IntRect clipRect = contentsToWindow(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect())); 2161 return intersection(clipRect, windowClipRect()); 2162 } 2163 2164 bool FrameView::isActive() const 2165 { 2166 Page* page = frame().page(); 2167 return page && page->focusController().isActive(); 2168 } 2169 2170 void FrameView::scrollTo(const IntSize& newOffset) 2171 { 2172 LayoutSize offset = scrollOffset(); 2173 ScrollView::scrollTo(newOffset); 2174 if (offset != scrollOffset()) { 2175 updateLayersAndCompositingAfterScrollIfNeeded(); 2176 scrollPositionChanged(); 2177 } 2178 frame().loader().client()->didChangeScrollOffset(); 2179 } 2180 2181 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) 2182 { 2183 // Add in our offset within the FrameView. 2184 IntRect dirtyRect = rect; 2185 dirtyRect.moveBy(scrollbar->location()); 2186 2187 if (isInPerformLayout()) 2188 addScrollbarDamage(scrollbar, rect); 2189 else 2190 invalidateRect(dirtyRect); 2191 } 2192 2193 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const 2194 { 2195 if (!m_tickmarks.isEmpty()) 2196 tickmarks = m_tickmarks; 2197 else 2198 tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch); 2199 } 2200 2201 IntRect FrameView::windowResizerRect() const 2202 { 2203 Page* page = frame().page(); 2204 if (!page) 2205 return IntRect(); 2206 return page->chrome().windowResizerRect(); 2207 } 2208 2209 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor) 2210 { 2211 if (m_visibleContentScaleFactor == visibleContentScaleFactor) 2212 return; 2213 2214 m_visibleContentScaleFactor = visibleContentScaleFactor; 2215 updateScrollbars(scrollOffset()); 2216 } 2217 2218 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor) 2219 { 2220 m_inputEventsOffsetForEmulation = offset; 2221 m_inputEventsScaleFactorForEmulation = contentScaleFactor; 2222 } 2223 2224 IntSize FrameView::inputEventsOffsetForEmulation() const 2225 { 2226 return m_inputEventsOffsetForEmulation; 2227 } 2228 2229 float FrameView::inputEventsScaleFactor() const 2230 { 2231 float pageScale = m_frame->settings()->pinchVirtualViewportEnabled() 2232 ? m_frame->page()->frameHost().pinchViewport().scale() 2233 : visibleContentScaleFactor(); 2234 return pageScale * m_inputEventsScaleFactorForEmulation; 2235 } 2236 2237 bool FrameView::scrollbarsCanBeActive() const 2238 { 2239 if (m_frame->view() != this) 2240 return false; 2241 2242 return !!m_frame->document(); 2243 } 2244 2245 IntRect FrameView::scrollableAreaBoundingBox() const 2246 { 2247 RenderPart* ownerRenderer = frame().ownerRenderer(); 2248 if (!ownerRenderer) 2249 return frameRect(); 2250 2251 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox(); 2252 } 2253 2254 2255 bool FrameView::isScrollable() 2256 { 2257 return scrollingReasons() == Scrollable; 2258 } 2259 2260 FrameView::ScrollingReasons FrameView::scrollingReasons() 2261 { 2262 // Check for: 2263 // 1) If there an actual overflow. 2264 // 2) display:none or visibility:hidden set to self or inherited. 2265 // 3) overflow{-x,-y}: hidden; 2266 // 4) scrolling: no; 2267 2268 // Covers #1 2269 IntSize contentsSize = this->contentsSize(); 2270 IntSize visibleContentSize = visibleContentRect().size(); 2271 if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width())) 2272 return NotScrollableNoOverflow; 2273 2274 // Covers #2. 2275 // FIXME: Do we need to fix this for OOPI? 2276 HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner(); 2277 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting())) 2278 return NotScrollableNotVisible; 2279 2280 // Cover #3 and #4. 2281 ScrollbarMode horizontalMode; 2282 ScrollbarMode verticalMode; 2283 calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly); 2284 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) 2285 return NotScrollableExplicitlyDisabled; 2286 2287 return Scrollable; 2288 } 2289 2290 void FrameView::updateScrollableAreaSet() 2291 { 2292 // That ensures that only inner frames are cached. 2293 FrameView* parentFrameView = this->parentFrameView(); 2294 if (!parentFrameView) 2295 return; 2296 2297 if (!isScrollable()) { 2298 parentFrameView->removeScrollableArea(this); 2299 return; 2300 } 2301 2302 parentFrameView->addScrollableArea(this); 2303 } 2304 2305 bool FrameView::shouldSuspendScrollAnimations() const 2306 { 2307 return m_frame->loader().state() != FrameStateComplete; 2308 } 2309 2310 void FrameView::scrollbarStyleChanged() 2311 { 2312 // FIXME: Why does this only apply to the main frame? 2313 if (!m_frame->isMainFrame()) 2314 return; 2315 ScrollView::scrollbarStyleChanged(); 2316 } 2317 2318 void FrameView::notifyPageThatContentAreaWillPaint() const 2319 { 2320 Page* page = m_frame->page(); 2321 if (!page) 2322 return; 2323 2324 contentAreaWillPaint(); 2325 2326 if (!m_scrollableAreas) 2327 return; 2328 2329 for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) { 2330 ScrollableArea* scrollableArea = *it; 2331 2332 if (!scrollableArea->scrollbarsCanBeActive()) 2333 continue; 2334 2335 scrollableArea->contentAreaWillPaint(); 2336 } 2337 } 2338 2339 bool FrameView::scrollAnimatorEnabled() const 2340 { 2341 return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled(); 2342 } 2343 2344 void FrameView::updateAnnotatedRegions() 2345 { 2346 Document* document = m_frame->document(); 2347 if (!document->hasAnnotatedRegions()) 2348 return; 2349 Vector<AnnotatedRegionValue> newRegions; 2350 document->renderBox()->collectAnnotatedRegions(newRegions); 2351 if (newRegions == document->annotatedRegions()) 2352 return; 2353 document->setAnnotatedRegions(newRegions); 2354 if (Page* page = m_frame->page()) 2355 page->chrome().client().annotatedRegionsChanged(); 2356 } 2357 2358 void FrameView::updateScrollCorner() 2359 { 2360 RefPtr<RenderStyle> cornerStyle; 2361 IntRect cornerRect = scrollCornerRect(); 2362 Document* doc = m_frame->document(); 2363 2364 if (doc && !cornerRect.isEmpty()) { 2365 // Try the <body> element first as a scroll corner source. 2366 if (Element* body = doc->body()) { 2367 if (RenderObject* renderer = body->renderer()) 2368 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); 2369 } 2370 2371 if (!cornerStyle) { 2372 // If the <body> didn't have a custom style, then the root element might. 2373 if (Element* docElement = doc->documentElement()) { 2374 if (RenderObject* renderer = docElement->renderer()) 2375 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); 2376 } 2377 } 2378 2379 if (!cornerStyle) { 2380 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also. 2381 if (RenderPart* renderer = m_frame->ownerRenderer()) 2382 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); 2383 } 2384 } 2385 2386 if (cornerStyle) { 2387 if (!m_scrollCorner) 2388 m_scrollCorner = RenderScrollbarPart::createAnonymous(doc); 2389 m_scrollCorner->setStyle(cornerStyle.release()); 2390 invalidateScrollCorner(cornerRect); 2391 } else if (m_scrollCorner) { 2392 m_scrollCorner->destroy(); 2393 m_scrollCorner = nullptr; 2394 } 2395 2396 ScrollView::updateScrollCorner(); 2397 } 2398 2399 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) 2400 { 2401 if (m_scrollCorner) { 2402 bool needsBackgorund = m_frame->isMainFrame(); 2403 if (needsBackgorund) 2404 context->fillRect(cornerRect, baseBackgroundColor()); 2405 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect); 2406 return; 2407 } 2408 2409 ScrollView::paintScrollCorner(context, cornerRect); 2410 } 2411 2412 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect) 2413 { 2414 bool needsBackgorund = bar->isCustomScrollbar() && m_frame->isMainFrame(); 2415 if (needsBackgorund) { 2416 IntRect toFill = bar->frameRect(); 2417 toFill.intersect(rect); 2418 context->fillRect(toFill, baseBackgroundColor()); 2419 } 2420 2421 ScrollView::paintScrollbar(context, bar, rect); 2422 } 2423 2424 Color FrameView::documentBackgroundColor() const 2425 { 2426 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of 2427 // the document and the body against the base background color of the frame view. 2428 // Background images are unfortunately impractical to include. 2429 2430 Color result = baseBackgroundColor(); 2431 if (!frame().document()) 2432 return result; 2433 2434 Element* htmlElement = frame().document()->documentElement(); 2435 Element* bodyElement = frame().document()->body(); 2436 2437 // We take the aggregate of the base background color 2438 // the <html> background color, and the <body> 2439 // background color to find the document color. The 2440 // addition of the base background color is not 2441 // technically part of the document background, but it 2442 // otherwise poses problems when the aggregate is not 2443 // fully opaque. 2444 if (htmlElement && htmlElement->renderer()) 2445 result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor)); 2446 if (bodyElement && bodyElement->renderer()) 2447 result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor)); 2448 2449 return result; 2450 } 2451 2452 bool FrameView::hasCustomScrollbars() const 2453 { 2454 const HashSet<RefPtr<Widget> >* viewChildren = children(); 2455 HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end(); 2456 for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { 2457 Widget* widget = current->get(); 2458 if (widget->isFrameView()) { 2459 if (toFrameView(widget)->hasCustomScrollbars()) 2460 return true; 2461 } else if (widget->isScrollbar()) { 2462 Scrollbar* scrollbar = static_cast<Scrollbar*>(widget); 2463 if (scrollbar->isCustomScrollbar()) 2464 return true; 2465 } 2466 } 2467 2468 return false; 2469 } 2470 2471 FrameView* FrameView::parentFrameView() const 2472 { 2473 if (!parent()) 2474 return 0; 2475 2476 Frame* parentFrame = m_frame->tree().parent(); 2477 if (parentFrame && parentFrame->isLocalFrame()) 2478 return toLocalFrame(parentFrame)->view(); 2479 2480 return 0; 2481 } 2482 2483 bool FrameView::wasScrolledByUser() const 2484 { 2485 return m_wasScrolledByUser; 2486 } 2487 2488 void FrameView::setWasScrolledByUser(bool wasScrolledByUser) 2489 { 2490 if (m_inProgrammaticScroll) 2491 return; 2492 m_maintainScrollPositionAnchor = nullptr; 2493 m_wasScrolledByUser = wasScrolledByUser; 2494 } 2495 2496 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) 2497 { 2498 Document* document = m_frame->document(); 2499 2500 #ifndef NDEBUG 2501 bool fillWithRed; 2502 if (document->printing()) 2503 fillWithRed = false; // Printing, don't fill with red (can't remember why). 2504 else if (m_frame->owner()) 2505 fillWithRed = false; // Subframe, don't fill with red. 2506 else if (isTransparent()) 2507 fillWithRed = false; // Transparent, don't fill with red. 2508 else if (m_paintBehavior & PaintBehaviorSelectionOnly) 2509 fillWithRed = false; // Selections are transparent, don't fill with red. 2510 else if (m_nodeToDraw) 2511 fillWithRed = false; // Element images are transparent, don't fill with red. 2512 else 2513 fillWithRed = true; 2514 2515 if (fillWithRed) 2516 p->fillRect(rect, Color(0xFF, 0, 0)); 2517 #endif 2518 2519 RenderView* renderView = this->renderView(); 2520 if (!renderView) { 2521 WTF_LOG_ERROR("called FrameView::paint with nil renderer"); 2522 return; 2523 } 2524 2525 RELEASE_ASSERT(!needsLayout()); 2526 ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); 2527 2528 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Paint", "data", InspectorPaintEvent::data(renderView, rect, 0)); 2529 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 2530 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 2531 InspectorInstrumentation::willPaint(renderView, 0); 2532 2533 bool isTopLevelPainter = !s_inPaintContents; 2534 s_inPaintContents = true; 2535 2536 FontCachePurgePreventer fontCachePurgePreventer; 2537 2538 PaintBehavior oldPaintBehavior = m_paintBehavior; 2539 2540 if (FrameView* parentView = parentFrameView()) { 2541 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers) 2542 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers; 2543 } 2544 2545 if (m_paintBehavior == PaintBehaviorNormal) 2546 document->markers().invalidateRenderedRectsForMarkersInRect(rect); 2547 2548 if (document->printing()) 2549 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers; 2550 2551 ASSERT(!m_isPainting); 2552 m_isPainting = true; 2553 2554 // m_nodeToDraw is used to draw only one element (and its descendants) 2555 RenderObject* renderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; 2556 RenderLayer* rootLayer = renderView->layer(); 2557 2558 #if ENABLE(ASSERT) 2559 renderView->assertSubtreeIsLaidOut(); 2560 RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->renderer()); 2561 #endif 2562 2563 rootLayer->paint(p, rect, m_paintBehavior, renderer); 2564 2565 if (rootLayer->containsDirtyOverlayScrollbars()) 2566 rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, renderer); 2567 2568 m_isPainting = false; 2569 2570 m_paintBehavior = oldPaintBehavior; 2571 m_lastPaintTime = currentTime(); 2572 2573 // Regions may have changed as a result of the visibility/z-index of element changing. 2574 if (document->annotatedRegionsDirty()) 2575 updateAnnotatedRegions(); 2576 2577 if (isTopLevelPainter) { 2578 // Everything that happens after paintContents completions is considered 2579 // to be part of the next frame. 2580 s_currentFrameTimeStamp = currentTime(); 2581 s_inPaintContents = false; 2582 } 2583 2584 InspectorInstrumentation::didPaint(renderView, 0, p, rect); 2585 } 2586 2587 void FrameView::setPaintBehavior(PaintBehavior behavior) 2588 { 2589 m_paintBehavior = behavior; 2590 } 2591 2592 PaintBehavior FrameView::paintBehavior() const 2593 { 2594 return m_paintBehavior; 2595 } 2596 2597 bool FrameView::isPainting() const 2598 { 2599 return m_isPainting; 2600 } 2601 2602 void FrameView::setNodeToDraw(Node* node) 2603 { 2604 m_nodeToDraw = node; 2605 } 2606 2607 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect) 2608 { 2609 if (m_frame->document()->printing()) 2610 return; 2611 2612 if (m_frame->isMainFrame()) { 2613 if (m_frame->page()->chrome().client().paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect)) 2614 return; 2615 } 2616 2617 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect); 2618 } 2619 2620 void FrameView::updateWidgetPositionsIfNeeded() 2621 { 2622 if (!m_needsUpdateWidgetPositions) 2623 return; 2624 2625 m_needsUpdateWidgetPositions = false; 2626 2627 updateWidgetPositions(); 2628 } 2629 2630 void FrameView::updateLayoutAndStyleForPainting() 2631 { 2632 // Updating layout can run script, which can tear down the FrameView. 2633 RefPtr<FrameView> protector(this); 2634 2635 updateLayoutAndStyleIfNeededRecursive(); 2636 2637 updateWidgetPositionsIfNeeded(); 2638 2639 if (RenderView* view = renderView()) { 2640 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateLayerTree", "frame", m_frame.get()); 2641 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 2642 InspectorInstrumentation::willUpdateLayerTree(m_frame.get()); 2643 2644 view->compositor()->updateIfNeededRecursive(); 2645 2646 if (view->compositor()->inCompositingMode() && m_frame->isLocalRoot()) 2647 m_frame->page()->scrollingCoordinator()->updateAfterCompositingChangeIfNeeded(); 2648 2649 updateCompositedSelectionBoundsIfNeeded(); 2650 2651 InspectorInstrumentation::didUpdateLayerTree(m_frame.get()); 2652 2653 invalidateTreeIfNeededRecursive(); 2654 } 2655 2656 scrollContentsIfNeededRecursive(); 2657 ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean); 2658 } 2659 2660 void FrameView::updateLayoutAndStyleIfNeededRecursive() 2661 { 2662 // We have to crawl our entire tree looking for any FrameViews that need 2663 // layout and make sure they are up to date. 2664 // Mac actually tests for intersection with the dirty region and tries not to 2665 // update layout for frames that are outside the dirty region. Not only does this seem 2666 // pointless (since those frames will have set a zero timer to layout anyway), but 2667 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty 2668 // region but then become included later by the second frame adding rects to the dirty region 2669 // when it lays out. 2670 2671 m_frame->document()->updateRenderTreeIfNeeded(); 2672 2673 if (needsLayout()) 2674 layout(); 2675 2676 // FIXME: Calling layout() shouldn't trigger scripe execution or have any 2677 // observable effects on the frame tree but we're not quite there yet. 2678 Vector<RefPtr<FrameView> > frameViews; 2679 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) { 2680 if (!child->isLocalFrame()) 2681 continue; 2682 if (FrameView* view = toLocalFrame(child)->view()) 2683 frameViews.append(view); 2684 } 2685 2686 const Vector<RefPtr<FrameView> >::iterator end = frameViews.end(); 2687 for (Vector<RefPtr<FrameView> >::iterator it = frameViews.begin(); it != end; ++it) 2688 (*it)->updateLayoutAndStyleIfNeededRecursive(); 2689 2690 // When an <iframe> gets composited, it triggers an extra style recalc in its containing FrameView. 2691 // To avoid pushing an invalid tree for display, we have to check for this case and do another 2692 // style recalc. The extra style recalc needs to happen after our child <iframes> were updated. 2693 // FIXME: We shouldn't be triggering an extra style recalc in the first place. 2694 if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) { 2695 m_frame->document()->updateRenderTreeIfNeeded(); 2696 2697 if (needsLayout()) 2698 layout(); 2699 } 2700 2701 // These asserts ensure that parent frames are clean, when child frames finished updating layout and style. 2702 ASSERT(!needsLayout()); 2703 ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()); 2704 #if ENABLE(ASSERT) 2705 m_frame->document()->renderView()->assertRendererLaidOut(); 2706 #endif 2707 2708 } 2709 2710 void FrameView::invalidateTreeIfNeededRecursive() 2711 { 2712 // FIXME: We should be more aggressive at cutting tree traversals. 2713 lifecycle().advanceTo(DocumentLifecycle::InPaintInvalidation); 2714 invalidateTreeIfNeeded(); 2715 lifecycle().advanceTo(DocumentLifecycle::PaintInvalidationClean); 2716 2717 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) { 2718 if (!child->isLocalFrame()) 2719 continue; 2720 2721 toLocalFrame(child)->view()->invalidateTreeIfNeededRecursive(); 2722 } 2723 2724 m_doFullPaintInvalidation = false; 2725 } 2726 2727 void FrameView::enableAutoSizeMode(const IntSize& minSize, const IntSize& maxSize) 2728 { 2729 if (!m_autoSizeInfo) 2730 m_autoSizeInfo = adoptPtr(new FrameViewAutoSizeInfo(this)); 2731 2732 m_autoSizeInfo->configureAutoSizeMode(minSize, maxSize); 2733 } 2734 2735 void FrameView::forceLayout(bool allowSubtree) 2736 { 2737 layout(allowSubtree); 2738 } 2739 2740 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor) 2741 { 2742 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see 2743 // the state of things before and after the layout 2744 if (RenderView* renderView = this->renderView()) { 2745 float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); 2746 float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); 2747 2748 LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); 2749 LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); 2750 renderView->setLogicalWidth(flooredPageLogicalWidth); 2751 renderView->setPageLogicalHeight(flooredPageLogicalHeight); 2752 renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); 2753 forceLayout(); 2754 2755 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the 2756 // page width when shrunk, we will lay out at maximum shrink and clip extra content. 2757 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping 2758 // implementation should not do this! 2759 bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode(); 2760 const LayoutRect& documentRect = renderView->documentRect(); 2761 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height(); 2762 if (docLogicalWidth > pageLogicalWidth) { 2763 FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor)); 2764 FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize); 2765 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height(); 2766 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width(); 2767 2768 flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); 2769 flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); 2770 renderView->setLogicalWidth(flooredPageLogicalWidth); 2771 renderView->setPageLogicalHeight(flooredPageLogicalHeight); 2772 renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); 2773 forceLayout(); 2774 2775 const LayoutRect& updatedDocumentRect = renderView->documentRect(); 2776 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width(); 2777 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x(); 2778 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY(); 2779 LayoutUnit clippedLogicalLeft = 0; 2780 if (!renderView->style()->isLeftToRightDirection()) 2781 clippedLogicalLeft = docLogicalRight - pageLogicalWidth; 2782 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight); 2783 2784 if (!horizontalWritingMode) 2785 overflow = overflow.transposedRect(); 2786 renderView->clearLayoutOverflow(); 2787 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. 2788 } 2789 } 2790 2791 adjustViewSize(); 2792 } 2793 2794 IntRect FrameView::convertFromRenderer(const RenderObject& renderer, const IntRect& rendererRect) const 2795 { 2796 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer.localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox())); 2797 2798 // Convert from page ("absolute") to FrameView coordinates. 2799 rect.moveBy(-scrollPosition()); 2800 2801 return rect; 2802 } 2803 2804 IntRect FrameView::convertToRenderer(const RenderObject& renderer, const IntRect& viewRect) const 2805 { 2806 IntRect rect = viewRect; 2807 2808 // Convert from FrameView coords into page ("absolute") coordinates. 2809 rect.moveBy(scrollPosition()); 2810 2811 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just 2812 // move the rect for now. 2813 rect.setLocation(roundedIntPoint(renderer.absoluteToLocal(rect.location(), UseTransforms))); 2814 return rect; 2815 } 2816 2817 IntPoint FrameView::convertFromRenderer(const RenderObject& renderer, const IntPoint& rendererPoint) const 2818 { 2819 IntPoint point = roundedIntPoint(renderer.localToAbsolute(rendererPoint, UseTransforms)); 2820 2821 // Convert from page ("absolute") to FrameView coordinates. 2822 point.moveBy(-scrollPosition()); 2823 return point; 2824 } 2825 2826 IntPoint FrameView::convertToRenderer(const RenderObject& renderer, const IntPoint& viewPoint) const 2827 { 2828 IntPoint point = viewPoint; 2829 2830 // Convert from FrameView coords into page ("absolute") coordinates. 2831 point += IntSize(scrollX(), scrollY()); 2832 2833 return roundedIntPoint(renderer.absoluteToLocal(point, UseTransforms)); 2834 } 2835 2836 IntRect FrameView::convertToContainingView(const IntRect& localRect) const 2837 { 2838 if (const ScrollView* parentScrollView = toScrollView(parent())) { 2839 if (parentScrollView->isFrameView()) { 2840 const FrameView* parentView = toFrameView(parentScrollView); 2841 // Get our renderer in the parent view 2842 RenderPart* renderer = m_frame->ownerRenderer(); 2843 if (!renderer) 2844 return localRect; 2845 2846 IntRect rect(localRect); 2847 // Add borders and padding?? 2848 rect.move(renderer->borderLeft() + renderer->paddingLeft(), 2849 renderer->borderTop() + renderer->paddingTop()); 2850 return parentView->convertFromRenderer(*renderer, rect); 2851 } 2852 2853 return Widget::convertToContainingView(localRect); 2854 } 2855 2856 return localRect; 2857 } 2858 2859 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const 2860 { 2861 if (const ScrollView* parentScrollView = toScrollView(parent())) { 2862 if (parentScrollView->isFrameView()) { 2863 const FrameView* parentView = toFrameView(parentScrollView); 2864 2865 // Get our renderer in the parent view 2866 RenderPart* renderer = m_frame->ownerRenderer(); 2867 if (!renderer) 2868 return parentRect; 2869 2870 IntRect rect = parentView->convertToRenderer(*renderer, parentRect); 2871 // Subtract borders and padding 2872 rect.move(-renderer->borderLeft() - renderer->paddingLeft(), 2873 -renderer->borderTop() - renderer->paddingTop()); 2874 return rect; 2875 } 2876 2877 return Widget::convertFromContainingView(parentRect); 2878 } 2879 2880 return parentRect; 2881 } 2882 2883 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const 2884 { 2885 if (const ScrollView* parentScrollView = toScrollView(parent())) { 2886 if (parentScrollView->isFrameView()) { 2887 const FrameView* parentView = toFrameView(parentScrollView); 2888 2889 // Get our renderer in the parent view 2890 RenderPart* renderer = m_frame->ownerRenderer(); 2891 if (!renderer) 2892 return localPoint; 2893 2894 IntPoint point(localPoint); 2895 2896 // Add borders and padding 2897 point.move(renderer->borderLeft() + renderer->paddingLeft(), 2898 renderer->borderTop() + renderer->paddingTop()); 2899 return parentView->convertFromRenderer(*renderer, point); 2900 } 2901 2902 return Widget::convertToContainingView(localPoint); 2903 } 2904 2905 return localPoint; 2906 } 2907 2908 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const 2909 { 2910 if (const ScrollView* parentScrollView = toScrollView(parent())) { 2911 if (parentScrollView->isFrameView()) { 2912 const FrameView* parentView = toFrameView(parentScrollView); 2913 2914 // Get our renderer in the parent view 2915 RenderPart* renderer = m_frame->ownerRenderer(); 2916 if (!renderer) 2917 return parentPoint; 2918 2919 IntPoint point = parentView->convertToRenderer(*renderer, parentPoint); 2920 // Subtract borders and padding 2921 point.move(-renderer->borderLeft() - renderer->paddingLeft(), 2922 -renderer->borderTop() - renderer->paddingTop()); 2923 return point; 2924 } 2925 2926 return Widget::convertFromContainingView(parentPoint); 2927 } 2928 2929 return parentPoint; 2930 } 2931 2932 void FrameView::setTracksPaintInvalidations(bool trackPaintInvalidations) 2933 { 2934 if (trackPaintInvalidations == m_isTrackingPaintInvalidations) 2935 return; 2936 2937 for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) { 2938 if (!frame->isLocalFrame()) 2939 continue; 2940 if (RenderView* renderView = toLocalFrame(frame)->contentRenderer()) 2941 renderView->compositor()->setTracksPaintInvalidations(trackPaintInvalidations); 2942 } 2943 2944 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), 2945 "FrameView::setTracksPaintInvalidations", "enabled", trackPaintInvalidations); 2946 2947 resetTrackedPaintInvalidations(); 2948 m_isTrackingPaintInvalidations = trackPaintInvalidations; 2949 } 2950 2951 void FrameView::resetTrackedPaintInvalidations() 2952 { 2953 m_trackedPaintInvalidationRects.clear(); 2954 if (RenderView* renderView = this->renderView()) 2955 renderView->compositor()->resetTrackedPaintInvalidationRects(); 2956 } 2957 2958 String FrameView::trackedPaintInvalidationRectsAsText() const 2959 { 2960 TextStream ts; 2961 if (!m_trackedPaintInvalidationRects.isEmpty()) { 2962 ts << "(repaint rects\n"; 2963 for (size_t i = 0; i < m_trackedPaintInvalidationRects.size(); ++i) 2964 ts << " (rect " << m_trackedPaintInvalidationRects[i].x() << " " << m_trackedPaintInvalidationRects[i].y() << " " << m_trackedPaintInvalidationRects[i].width() << " " << m_trackedPaintInvalidationRects[i].height() << ")\n"; 2965 ts << ")\n"; 2966 } 2967 return ts.release(); 2968 } 2969 2970 void FrameView::addResizerArea(RenderBox& resizerBox) 2971 { 2972 if (!m_resizerAreas) 2973 m_resizerAreas = adoptPtr(new ResizerAreaSet); 2974 m_resizerAreas->add(&resizerBox); 2975 } 2976 2977 void FrameView::removeResizerArea(RenderBox& resizerBox) 2978 { 2979 if (!m_resizerAreas) 2980 return; 2981 2982 ResizerAreaSet::iterator it = m_resizerAreas->find(&resizerBox); 2983 if (it != m_resizerAreas->end()) 2984 m_resizerAreas->remove(it); 2985 } 2986 2987 void FrameView::addScrollableArea(ScrollableArea* scrollableArea) 2988 { 2989 ASSERT(scrollableArea); 2990 if (!m_scrollableAreas) 2991 m_scrollableAreas = adoptPtr(new ScrollableAreaSet); 2992 m_scrollableAreas->add(scrollableArea); 2993 } 2994 2995 void FrameView::removeScrollableArea(ScrollableArea* scrollableArea) 2996 { 2997 if (!m_scrollableAreas) 2998 return; 2999 m_scrollableAreas->remove(scrollableArea); 3000 } 3001 3002 void FrameView::setParent(Widget* widget) 3003 { 3004 ScrollView::setParent(widget); 3005 updateScrollableAreaSet(); 3006 } 3007 3008 void FrameView::removeChild(Widget* widget) 3009 { 3010 if (widget->isFrameView()) 3011 removeScrollableArea(toFrameView(widget)); 3012 3013 ScrollView::removeChild(widget); 3014 } 3015 3016 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) 3017 { 3018 bool allowScrolling = userInputScrollable(HorizontalScrollbar) || userInputScrollable(VerticalScrollbar); 3019 3020 // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views 3021 // should handle wheel events. 3022 #if !USE(RUBBER_BANDING) 3023 if (!isScrollable()) 3024 allowScrolling = false; 3025 #endif 3026 3027 if (allowScrolling && ScrollableArea::handleWheelEvent(wheelEvent)) 3028 return true; 3029 3030 // If the frame didn't handle the event, give the pinch-zoom viewport a chance to 3031 // process the scroll event. 3032 if (m_frame->settings()->pinchVirtualViewportEnabled() && m_frame->isMainFrame()) 3033 return page()->frameHost().pinchViewport().handleWheelEvent(wheelEvent); 3034 3035 return false; 3036 } 3037 3038 bool FrameView::isVerticalDocument() const 3039 { 3040 RenderView* renderView = this->renderView(); 3041 if (!renderView) 3042 return true; 3043 3044 return renderView->style()->isHorizontalWritingMode(); 3045 } 3046 3047 bool FrameView::isFlippedDocument() const 3048 { 3049 RenderView* renderView = this->renderView(); 3050 if (!renderView) 3051 return false; 3052 3053 return renderView->style()->isFlippedBlocksWritingMode(); 3054 } 3055 3056 bool FrameView::scrollbarsDisabled() const 3057 { 3058 if (!m_frame->settings() || !m_frame->settings()->pinchVirtualViewportEnabled()) 3059 return false; 3060 3061 return m_frame->isMainFrame() && ScrollbarTheme::theme()->usesOverlayScrollbars(); 3062 } 3063 3064 AXObjectCache* FrameView::axObjectCache() const 3065 { 3066 if (frame().document()) 3067 return frame().document()->existingAXObjectCache(); 3068 return 0; 3069 } 3070 3071 void FrameView::setCursor(const Cursor& cursor) 3072 { 3073 Page* page = frame().page(); 3074 if (!page || !page->settings().deviceSupportsMouse()) 3075 return; 3076 page->chrome().setCursor(cursor); 3077 } 3078 3079 void FrameView::frameRectsChanged() 3080 { 3081 if (layoutSizeFixedToFrameSize()) 3082 setLayoutSizeInternal(frameRect().size()); 3083 3084 ScrollView::frameRectsChanged(); 3085 } 3086 3087 void FrameView::setLayoutSizeInternal(const IntSize& size) 3088 { 3089 if (m_layoutSize == size) 3090 return; 3091 3092 m_layoutSize = size; 3093 contentsResized(); 3094 } 3095 3096 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) 3097 { 3098 ScrollableArea::didAddScrollbar(scrollbar, orientation); 3099 if (AXObjectCache* cache = axObjectCache()) 3100 cache->handleScrollbarUpdate(this); 3101 } 3102 3103 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) 3104 { 3105 ScrollableArea::willRemoveScrollbar(scrollbar, orientation); 3106 if (AXObjectCache* cache = axObjectCache()) { 3107 cache->remove(scrollbar); 3108 cache->handleScrollbarUpdate(this); 3109 } 3110 } 3111 3112 void FrameView::setTopControlsViewportAdjustment(float adjustment) 3113 { 3114 m_topControlsViewportAdjustment = adjustment; 3115 } 3116 3117 IntPoint FrameView::maximumScrollPosition() const 3118 { 3119 FloatSize visibleContentSizeF = unscaledVisibleContentSize(ExcludeScrollbars); 3120 visibleContentSizeF.expand(0, -m_topControlsViewportAdjustment); 3121 visibleContentSizeF.scale(1 / visibleContentScaleFactor()); 3122 IntSize visibleSize = expandedIntSize(visibleContentSizeF); 3123 3124 IntPoint maximumOffset( 3125 contentsWidth() - visibleSize.width() - scrollOrigin().x(), 3126 contentsHeight() - visibleSize.height() - scrollOrigin().y()); 3127 maximumOffset.clampNegativeToZero(); 3128 return maximumOffset; 3129 } 3130 3131 } // namespace blink 3132