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