1/* 2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 3 * 1999 Lars Knoll <knoll@kde.org> 4 * 1999 Antti Koivisto <koivisto@kde.org> 5 * 2000 Dirk Mueller <mueller@kde.org> 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. 7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) 8 * (C) 2006 Alexey Proskuryakov (ap@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 "FrameView.h" 29 30#include "AXObjectCache.h" 31#include "AnimationController.h" 32#include "BackForwardController.h" 33#include "CachedImage.h" 34#include "CachedResourceLoader.h" 35#include "Chrome.h" 36#include "ChromeClient.h" 37#include "DOMWindow.h" 38#include "DocumentMarkerController.h" 39#include "EventHandler.h" 40#include "FloatRect.h" 41#include "FocusController.h" 42#include "FontCache.h" 43#include "FontLoader.h" 44#include "FrameLoader.h" 45#include "FrameLoaderClient.h" 46#include "FrameSelection.h" 47#include "FrameTree.h" 48#include "GraphicsContext.h" 49#include "HTMLDocument.h" 50#include "HTMLFrameElement.h" 51#include "HTMLFrameSetElement.h" 52#include "HTMLNames.h" 53#include "HTMLPlugInImageElement.h" 54#include "ImageDocument.h" 55#include "InspectorClient.h" 56#include "InspectorController.h" 57#include "InspectorInstrumentation.h" 58#include "Logging.h" 59#include "MainFrame.h" 60#include "MemoryCache.h" 61#include "MemoryPressureHandler.h" 62#include "OverflowEvent.h" 63#include "ProgressTracker.h" 64#include "RenderEmbeddedObject.h" 65#include "RenderFullScreen.h" 66#include "RenderIFrame.h" 67#include "RenderInline.h" 68#include "RenderLayer.h" 69#include "RenderLayerBacking.h" 70#include "RenderLayerCompositor.h" 71#include "RenderSVGRoot.h" 72#include "RenderScrollbar.h" 73#include "RenderScrollbarPart.h" 74#include "RenderStyle.h" 75#include "RenderText.h" 76#include "RenderTheme.h" 77#include "RenderView.h" 78#include "RenderWidget.h" 79#include "SVGDocument.h" 80#include "SVGSVGElement.h" 81#include "ScrollAnimator.h" 82#include "ScrollingCoordinator.h" 83#include "Settings.h" 84#include "StyleResolver.h" 85#include "TextResourceDecoder.h" 86#include "TextStream.h" 87#include "TiledBacking.h" 88 89#include <wtf/CurrentTime.h> 90#include <wtf/Ref.h> 91#include <wtf/TemporaryChange.h> 92 93#if USE(TILED_BACKING_STORE) 94#include "TiledBackingStore.h" 95#endif 96 97#if ENABLE(TEXT_AUTOSIZING) 98#include "TextAutosizer.h" 99#endif 100 101#if PLATFORM(IOS) 102#include "DocumentLoader.h" 103#include "LegacyTileCache.h" 104#include "MemoryCache.h" 105#include "MemoryPressureHandler.h" 106#include "SystemMemory.h" 107#endif 108 109namespace WebCore { 110 111using namespace HTMLNames; 112 113double FrameView::sCurrentPaintTimeStamp = 0.0; 114 115// The maximum number of updateEmbeddedObjects iterations that should be done before returning. 116static const unsigned maxUpdateEmbeddedObjectsIterations = 2; 117 118static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint) 119{ 120 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags; 121 if (didFullRepaint) { 122 flags &= ~RenderLayer::CheckForRepaint; 123 flags |= RenderLayer::NeedsFullRepaintInBacking; 124 } 125 if (isRelayoutingSubtree && layer->enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers)) 126 flags |= RenderLayer::UpdatePagination; 127 return flags; 128} 129 130Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style) 131{ 132 EOverflow overflow = style.overflowY(); 133 if (overflow != OPAGEDX && overflow != OPAGEDY) 134 return Pagination::Unpaginated; 135 136 bool isHorizontalWritingMode = style.isHorizontalWritingMode(); 137 TextDirection textDirection = style.direction(); 138 WritingMode writingMode = style.writingMode(); 139 140 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode 141 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode 142 // is vertical, then the direction of the verticality dictates the choice. 143 if (overflow == OPAGEDX) { 144 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode) 145 return Pagination::LeftToRightPaginated; 146 return Pagination::RightToLeftPaginated; 147 } 148 149 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode 150 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode 151 // is vertical, then we use TextDirection to choose between those options. 152 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL)) 153 return Pagination::TopToBottomPaginated; 154 return Pagination::BottomToTopPaginated; 155} 156 157FrameView::FrameView(Frame& frame) 158 : m_frame(&frame) 159 , m_canHaveScrollbars(true) 160 , m_layoutTimer(this, &FrameView::layoutTimerFired) 161 , m_layoutRoot(0) 162 , m_layoutPhase(OutsideLayout) 163 , m_inSynchronousPostLayout(false) 164 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) 165 , m_updateEmbeddedObjectsTimer(this, &FrameView::updateEmbeddedObjectsTimerFired) 166 , m_isTransparent(false) 167 , m_baseBackgroundColor(Color::white) 168 , m_mediaType("screen") 169 , m_overflowStatusDirty(true) 170 , m_viewportRenderer(0) 171 , m_wasScrolledByUser(false) 172 , m_inProgrammaticScroll(false) 173 , m_safeToPropagateScrollToParent(true) 174 , m_delayedScrollEventTimer(this, &FrameView::delayedScrollEventTimerFired) 175 , m_isTrackingRepaints(false) 176 , m_shouldUpdateWhileOffscreen(true) 177 , m_exposedRect(FloatRect::infiniteRect()) 178 , m_deferSetNeedsLayouts(0) 179 , m_setNeedsLayoutWasDeferred(false) 180 , m_speculativeTilingEnabled(false) 181 , m_speculativeTilingEnableTimer(this, &FrameView::speculativeTilingEnableTimerFired) 182#if PLATFORM(IOS) 183 , m_useCustomFixedPositionLayoutRect(false) 184 , m_useCustomSizeForResizeEvent(false) 185#endif 186 , m_hasOverrideViewportSize(false) 187 , m_shouldAutoSize(false) 188 , m_inAutoSize(false) 189 , m_didRunAutosize(false) 190 , m_autoSizeFixedMinimumHeight(0) 191 , m_headerHeight(0) 192 , m_footerHeight(0) 193 , m_milestonesPendingPaint(0) 194 , m_visualUpdatesAllowedByClient(true) 195 , m_scrollPinningBehavior(DoNotPin) 196{ 197 init(); 198 199 if (frame.isMainFrame()) { 200 ScrollableArea::setVerticalScrollElasticity(m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed); 201 ScrollableArea::setHorizontalScrollElasticity(m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed); 202 } 203} 204 205PassRefPtr<FrameView> FrameView::create(Frame& frame) 206{ 207 RefPtr<FrameView> view = adoptRef(new FrameView(frame)); 208 view->show(); 209 return view.release(); 210} 211 212PassRefPtr<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize) 213{ 214 RefPtr<FrameView> view = adoptRef(new FrameView(frame)); 215 view->Widget::setFrameRect(IntRect(view->location(), initialSize)); 216 view->show(); 217 return view.release(); 218} 219 220FrameView::~FrameView() 221{ 222 if (m_postLayoutTasksTimer.isActive()) 223 m_postLayoutTasksTimer.stop(); 224 225 removeFromAXObjectCache(); 226 resetScrollbars(); 227 228 // Custom scrollbars should already be destroyed at this point 229 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar()); 230 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar()); 231 232 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow. 233 setHasVerticalScrollbar(false); 234 235 ASSERT(!m_scrollCorner); 236 237 ASSERT(frame().view() != this || !frame().contentRenderer()); 238} 239 240void FrameView::reset() 241{ 242 m_cannotBlitToWindow = false; 243 m_isOverlapped = false; 244 m_contentIsOpaque = false; 245 m_layoutTimer.stop(); 246 m_layoutRoot = 0; 247 m_delayedLayout = false; 248 m_needsFullRepaint = true; 249 m_layoutSchedulingEnabled = true; 250 m_layoutPhase = OutsideLayout; 251 m_inSynchronousPostLayout = false; 252 m_layoutCount = 0; 253 m_nestedLayoutCount = 0; 254 m_postLayoutTasksTimer.stop(); 255 m_updateEmbeddedObjectsTimer.stop(); 256 m_firstLayout = true; 257 m_firstLayoutCallbackPending = false; 258 m_wasScrolledByUser = false; 259 m_safeToPropagateScrollToParent = true; 260 m_delayedScrollEventTimer.stop(); 261 m_lastViewportSize = IntSize(); 262 m_lastZoomFactor = 1.0f; 263 m_isTrackingRepaints = false; 264 m_trackedRepaintRects.clear(); 265 m_lastPaintTime = 0; 266 m_paintBehavior = PaintBehaviorNormal; 267 m_isPainting = false; 268 m_visuallyNonEmptyCharacterCount = 0; 269 m_visuallyNonEmptyPixelCount = 0; 270 m_isVisuallyNonEmpty = false; 271 m_firstVisuallyNonEmptyLayoutCallbackPending = true; 272 m_maintainScrollPositionAnchor = 0; 273} 274 275void FrameView::removeFromAXObjectCache() 276{ 277 if (AXObjectCache* cache = axObjectCache()) 278 cache->remove(this); 279} 280 281void FrameView::resetScrollbars() 282{ 283 // Reset the document's scrollbars back to our defaults before we yield the floor. 284 m_firstLayout = true; 285 setScrollbarsSuppressed(true); 286 if (m_canHaveScrollbars) 287 setScrollbarModes(ScrollbarAuto, ScrollbarAuto); 288 else 289 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); 290 setScrollbarsSuppressed(false); 291} 292 293void FrameView::resetScrollbarsAndClearContentsSize() 294{ 295 resetScrollbars(); 296 297 setScrollbarsSuppressed(true); 298 setContentsSize(IntSize()); 299 setScrollbarsSuppressed(false); 300} 301 302void FrameView::init() 303{ 304 reset(); 305 306 m_margins = LayoutSize(-1, -1); // undefined 307 m_size = LayoutSize(); 308 309 // Propagate the marginwidth/height and scrolling modes to the view. 310 Element* ownerElement = frame().ownerElement(); 311 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { 312 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement); 313 if (frameElt->scrollingMode() == ScrollbarAlwaysOff) 314 setCanHaveScrollbars(false); 315 LayoutUnit marginWidth = frameElt->marginWidth(); 316 LayoutUnit marginHeight = frameElt->marginHeight(); 317 if (marginWidth != -1) 318 setMarginWidth(marginWidth); 319 if (marginHeight != -1) 320 setMarginHeight(marginHeight); 321 } 322 323 Page* page = frame().page(); 324 if (page && page->chrome().client().shouldPaintEntireContents()) 325 setPaintsEntireContents(true); 326} 327 328void FrameView::prepareForDetach() 329{ 330 detachCustomScrollbars(); 331 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache 332 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later. 333 removeFromAXObjectCache(); 334 335 if (frame().page()) { 336 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator()) 337 scrollingCoordinator->willDestroyScrollableArea(this); 338 } 339} 340 341void FrameView::detachCustomScrollbars() 342{ 343 Scrollbar* horizontalBar = horizontalScrollbar(); 344 if (horizontalBar && horizontalBar->isCustomScrollbar()) 345 setHasHorizontalScrollbar(false); 346 347 Scrollbar* verticalBar = verticalScrollbar(); 348 if (verticalBar && verticalBar->isCustomScrollbar()) 349 setHasVerticalScrollbar(false); 350 351 m_scrollCorner = nullptr; 352} 353 354void FrameView::recalculateScrollbarOverlayStyle() 355{ 356 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle(); 357 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; 358 359 Color backgroundColor = documentBackgroundColor(); 360 if (backgroundColor.isValid()) { 361 // Reduce the background color from RGB to a lightness value 362 // and determine which scrollbar style to use based on a lightness 363 // heuristic. 364 double hue, saturation, lightness; 365 backgroundColor.getHSL(hue, saturation, lightness); 366 if (lightness <= .5 && backgroundColor.alpha() > 0) 367 overlayStyle = ScrollbarOverlayStyleLight; 368 } 369 370 if (oldOverlayStyle != overlayStyle) 371 setScrollbarOverlayStyle(overlayStyle); 372} 373 374void FrameView::clear() 375{ 376 setCanBlitOnScroll(true); 377 378 reset(); 379 380 setScrollbarsSuppressed(true); 381 382#if PLATFORM(IOS) 383 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load. 384 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw. 385 if (LegacyTileCache* tileCache = legacyTileCache()) 386 tileCache->setTilingMode(LegacyTileCache::Disabled); 387#endif 388} 389 390bool FrameView::didFirstLayout() const 391{ 392 return !m_firstLayout; 393} 394 395void FrameView::invalidateRect(const IntRect& rect) 396{ 397 if (!parent()) { 398 if (HostWindow* window = hostWindow()) 399 window->invalidateContentsAndRootView(rect); 400 return; 401 } 402 403 RenderWidget* renderer = frame().ownerRenderer(); 404 if (!renderer) 405 return; 406 407 IntRect repaintRect = rect; 408 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), 409 renderer->borderTop() + renderer->paddingTop()); 410 renderer->repaintRectangle(repaintRect); 411} 412 413void FrameView::setFrameRect(const IntRect& newRect) 414{ 415 IntRect oldRect = frameRect(); 416 if (newRect == oldRect) 417 return; 418 419#if ENABLE(TEXT_AUTOSIZING) 420 // Autosized font sizes depend on the width of the viewing area. 421 if (newRect.width() != oldRect.width()) { 422 Page* page = frame().page(); 423 if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) { 424 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) 425 frame().document()->textAutosizer()->recalculateMultipliers(); 426 } 427 } 428#endif 429 430 ScrollView::setFrameRect(newRect); 431 432 updateScrollableAreaSet(); 433 434 if (RenderView* renderView = this->renderView()) { 435 if (renderView->usesCompositing()) 436 renderView->compositor().frameViewDidChangeSize(); 437 } 438} 439 440#if ENABLE(REQUEST_ANIMATION_FRAME) 441bool FrameView::scheduleAnimation() 442{ 443 if (HostWindow* window = hostWindow()) { 444 window->scheduleAnimation(); 445 return true; 446 } 447 return false; 448} 449#endif 450 451void FrameView::setMarginWidth(LayoutUnit w) 452{ 453 // make it update the rendering area when set 454 m_margins.setWidth(w); 455} 456 457void FrameView::setMarginHeight(LayoutUnit h) 458{ 459 // make it update the rendering area when set 460 m_margins.setHeight(h); 461} 462 463bool FrameView::frameFlatteningEnabled() const 464{ 465 return frame().settings().frameFlatteningEnabled(); 466} 467 468bool FrameView::isFrameFlatteningValidForThisFrame() const 469{ 470 if (!frameFlatteningEnabled()) 471 return false; 472 473 HTMLFrameOwnerElement* owner = frame().ownerElement(); 474 if (!owner) 475 return false; 476 477 // Frame flattening is valid only for <frame> and <iframe>. 478 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag); 479} 480 481bool FrameView::avoidScrollbarCreation() const 482{ 483 // with frame flattening no subframe can have scrollbars 484 // but we also cannot turn scrollbars off as we determine 485 // our flattening policy using that. 486 return isFrameFlatteningValidForThisFrame(); 487} 488 489void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) 490{ 491 m_canHaveScrollbars = canHaveScrollbars; 492 ScrollView::setCanHaveScrollbars(canHaveScrollbars); 493} 494 495void FrameView::updateCanHaveScrollbars() 496{ 497 ScrollbarMode hMode; 498 ScrollbarMode vMode; 499 scrollbarModes(hMode, vMode); 500 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff) 501 setCanHaveScrollbars(false); 502 else 503 setCanHaveScrollbars(true); 504} 505 506PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) 507{ 508 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame()) 509 return ScrollView::createScrollbar(orientation); 510 511 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). 512 Document* doc = frame().document(); 513 514 // Try the <body> element first as a scrollbar source. 515 Element* body = doc ? doc->body() : 0; 516 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR)) 517 return RenderScrollbar::createCustomScrollbar(this, orientation, body); 518 519 // If the <body> didn't have a custom style, then the root element might. 520 Element* docElement = doc ? doc->documentElement() : 0; 521 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR)) 522 return RenderScrollbar::createCustomScrollbar(this, orientation, docElement); 523 524 // If we have an owning iframe/frame element, then it can set the custom scrollbar also. 525 RenderWidget* frameRenderer = frame().ownerRenderer(); 526 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR)) 527 return RenderScrollbar::createCustomScrollbar(this, orientation, 0, &frame()); 528 529 // Nobody set a custom style, so we just use a native scrollbar. 530 return ScrollView::createScrollbar(orientation); 531} 532 533void FrameView::setContentsSize(const IntSize& size) 534{ 535 if (size == contentsSize()) 536 return; 537 538 m_deferSetNeedsLayouts++; 539 540 ScrollView::setContentsSize(size); 541 ScrollView::contentsResized(); 542 543 Page* page = frame().page(); 544 if (!page) 545 return; 546 547 updateScrollableAreaSet(); 548 549 page->chrome().contentsSizeChanged(&frame(), size); // Notify only. 550 551 ASSERT(m_deferSetNeedsLayouts); 552 m_deferSetNeedsLayouts--; 553 554 if (!m_deferSetNeedsLayouts) 555 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen. 556} 557 558void FrameView::adjustViewSize() 559{ 560 RenderView* renderView = this->renderView(); 561 if (!renderView) 562 return; 563 564 ASSERT(frame().view() == this); 565 566 const IntRect rect = renderView->documentRect(); 567 const IntSize& size = rect.size(); 568 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize()); 569 570 setContentsSize(size); 571} 572 573void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, ScrollbarMode& vMode) 574{ 575 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats 576 // overflow:hidden and overflow:scroll on <body> as applying to the document's 577 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should 578 // use the root element. 579 580 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when 581 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a 582 // header or footer. 583 584 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight()); 585 586 EOverflow overflowX = o->style().overflowX(); 587 EOverflow overflowY = o->style().overflowY(); 588 589 if (o->isSVGRoot()) { 590 // FIXME: evaluate if we can allow overflow for these cases too. 591 // Overflow is always hidden when stand-alone SVG documents are embedded. 592 if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) { 593 overflowX = OHIDDEN; 594 overflowY = OHIDDEN; 595 } 596 } 597 598 switch (overflowX) { 599 case OHIDDEN: 600 if (overrideHidden) 601 hMode = ScrollbarAuto; 602 else 603 hMode = ScrollbarAlwaysOff; 604 break; 605 case OSCROLL: 606 hMode = ScrollbarAlwaysOn; 607 break; 608 case OAUTO: 609 hMode = ScrollbarAuto; 610 break; 611 default: 612 // Don't set it at all. 613 ; 614 } 615 616 switch (overflowY) { 617 case OHIDDEN: 618 if (overrideHidden) 619 vMode = ScrollbarAuto; 620 else 621 vMode = ScrollbarAlwaysOff; 622 break; 623 case OSCROLL: 624 vMode = ScrollbarAlwaysOn; 625 break; 626 case OAUTO: 627 vMode = ScrollbarAuto; 628 break; 629 default: 630 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort(). 631 ; 632 } 633 634 m_viewportRenderer = o; 635} 636 637void FrameView::applyPaginationToViewport() 638{ 639 Document* document = frame().document(); 640 auto documentElement = document->documentElement(); 641 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr; 642 RenderElement* documentOrBodyRenderer = documentRenderer; 643 auto body = document->body(); 644 if (body && body->renderer()) { 645 if (body->hasTagName(bodyTag)) 646 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer; 647 } 648 649 Pagination pagination; 650 651 if (!documentOrBodyRenderer) { 652 setPagination(pagination); 653 return; 654 } 655 656 EOverflow overflowY = documentOrBodyRenderer->style().overflowY(); 657 if (overflowY == OPAGEDX || overflowY == OPAGEDY) { 658 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style()); 659 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap()); 660 } 661 662 setPagination(pagination); 663} 664 665void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy) 666{ 667 m_viewportRenderer = 0; 668 669 const HTMLFrameOwnerElement* owner = frame().ownerElement(); 670 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) { 671 hMode = ScrollbarAlwaysOff; 672 vMode = ScrollbarAlwaysOff; 673 return; 674 } 675 676 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { 677 hMode = ScrollbarAuto; 678 vMode = ScrollbarAuto; 679 } else { 680 hMode = ScrollbarAlwaysOff; 681 vMode = ScrollbarAlwaysOff; 682 } 683 684 if (!m_layoutRoot) { 685 Document* document = frame().document(); 686 auto documentElement = document->documentElement(); 687 RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr; 688 auto body = document->body(); 689 if (body && body->renderer()) { 690 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { 691 vMode = ScrollbarAlwaysOff; 692 hMode = ScrollbarAlwaysOff; 693 } else if (body->hasTagName(bodyTag)) { 694 // It's sufficient to just check the X overflow, 695 // since it's illegal to have visible in only one direction. 696 RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer; 697 applyOverflowToViewport(o, hMode, vMode); 698 } 699 } else if (rootRenderer) 700 applyOverflowToViewport(rootRenderer, hMode, vMode); 701 } 702} 703 704void FrameView::updateCompositingLayersAfterStyleChange() 705{ 706 RenderView* renderView = this->renderView(); 707 if (!renderView) 708 return; 709 710 // If we expect to update compositing after an incipient layout, don't do so here. 711 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout()) 712 return; 713 714 RenderLayerCompositor& compositor = renderView->compositor(); 715 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref 716 compositor.cacheAcceleratedCompositingFlags(); 717 compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange); 718} 719 720void FrameView::updateCompositingLayersAfterLayout() 721{ 722 RenderView* renderView = this->renderView(); 723 if (!renderView) 724 return; 725 726 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref 727 renderView->compositor().cacheAcceleratedCompositingFlags(); 728 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout); 729} 730 731void FrameView::clearBackingStores() 732{ 733 RenderView* renderView = this->renderView(); 734 if (!renderView) 735 return; 736 737 RenderLayerCompositor& compositor = renderView->compositor(); 738 ASSERT(compositor.inCompositingMode()); 739 compositor.enableCompositingMode(false); 740 compositor.clearBackingForAllLayers(); 741} 742 743void FrameView::restoreBackingStores() 744{ 745 RenderView* renderView = this->renderView(); 746 if (!renderView) 747 return; 748 749 RenderLayerCompositor& compositor = renderView->compositor(); 750 compositor.enableCompositingMode(true); 751 compositor.updateCompositingLayers(CompositingUpdateAfterLayout); 752} 753 754GraphicsLayer* FrameView::layerForScrolling() const 755{ 756 RenderView* renderView = this->renderView(); 757 if (!renderView) 758 return 0; 759 return renderView->compositor().scrollLayer(); 760} 761 762GraphicsLayer* FrameView::layerForHorizontalScrollbar() const 763{ 764 RenderView* renderView = this->renderView(); 765 if (!renderView) 766 return 0; 767 return renderView->compositor().layerForHorizontalScrollbar(); 768} 769 770GraphicsLayer* FrameView::layerForVerticalScrollbar() const 771{ 772 RenderView* renderView = this->renderView(); 773 if (!renderView) 774 return 0; 775 return renderView->compositor().layerForVerticalScrollbar(); 776} 777 778GraphicsLayer* FrameView::layerForScrollCorner() const 779{ 780 RenderView* renderView = this->renderView(); 781 if (!renderView) 782 return 0; 783 return renderView->compositor().layerForScrollCorner(); 784} 785 786TiledBacking* FrameView::tiledBacking() const 787{ 788 RenderView* renderView = this->renderView(); 789 if (!renderView) 790 return 0; 791 792 RenderLayerBacking* backing = renderView->layer()->backing(); 793 if (!backing) 794 return 0; 795 796 return backing->graphicsLayer()->tiledBacking(); 797} 798 799uint64_t FrameView::scrollLayerID() const 800{ 801 RenderView* renderView = this->renderView(); 802 if (!renderView) 803 return 0; 804 805 RenderLayerBacking* backing = renderView->layer()->backing(); 806 if (!backing) 807 return 0; 808 809 return backing->scrollingNodeIDForRole(FrameScrollingNode); 810} 811 812ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const 813{ 814 RenderView* renderView = this->renderView(); 815 if (!renderView) 816 return nullptr; 817 818 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID); 819} 820 821#if ENABLE(RUBBER_BANDING) 822GraphicsLayer* FrameView::layerForOverhangAreas() const 823{ 824 RenderView* renderView = this->renderView(); 825 if (!renderView) 826 return 0; 827 return renderView->compositor().layerForOverhangAreas(); 828} 829 830GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const 831{ 832 RenderView* renderView = this->renderView(); 833 if (!renderView) 834 return 0; 835 836 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer); 837} 838 839GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const 840{ 841 RenderView* renderView = this->renderView(); 842 if (!renderView) 843 return 0; 844 845 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer); 846} 847 848#endif // ENABLE(RUBBER_BANDING) 849 850bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) 851{ 852 RenderView* renderView = this->renderView(); 853 if (!renderView) 854 return true; // We don't want to keep trying to update layers if we have no renderer. 855 856 ASSERT(frame().view() == this); 857 858 // If we sync compositing layers when a layout is pending, we may cause painting of compositing 859 // layer content to occur before layout has happened, which will cause paintContents() to bail. 860 if (needsLayout()) 861 return false; 862 863#if PLATFORM(IOS) 864 if (LegacyTileCache* tileCache = legacyTileCache()) 865 tileCache->doPendingRepaints(); 866#endif 867 868 renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame()); 869 870 return true; 871} 872 873void FrameView::setNeedsOneShotDrawingSynchronization() 874{ 875 if (Page* page = frame().page()) 876 page->chrome().client().setNeedsOneShotDrawingSynchronization(); 877} 878 879GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget) 880{ 881 // To find the Widget that corresponds with platformWidget we have to do a linear 882 // search of our child widgets. 883 Widget* foundWidget = nullptr; 884 for (auto& widget : children()) { 885 if (widget->platformWidget() != platformWidget) 886 continue; 887 foundWidget = widget.get(); 888 break; 889 } 890 891 if (!foundWidget) 892 return nullptr; 893 894 auto* renderWidget = RenderWidget::find(foundWidget); 895 if (!renderWidget) 896 return nullptr; 897 898 RenderLayer* widgetLayer = renderWidget->layer(); 899 if (!widgetLayer || !widgetLayer->isComposited()) 900 return nullptr; 901 902 return widgetLayer->backing()->parentForSublayers(); 903} 904 905void FrameView::scheduleLayerFlushAllowingThrottling() 906{ 907 RenderView* view = this->renderView(); 908 if (!view) 909 return; 910 view->compositor().scheduleLayerFlush(true /* canThrottle */); 911} 912 913void FrameView::setHeaderHeight(int headerHeight) 914{ 915 if (frame().page()) 916 ASSERT(frame().isMainFrame()); 917 m_headerHeight = headerHeight; 918 919 if (RenderView* renderView = this->renderView()) 920 renderView->setNeedsLayout(); 921} 922 923void FrameView::setFooterHeight(int footerHeight) 924{ 925 if (frame().page()) 926 ASSERT(frame().isMainFrame()); 927 m_footerHeight = footerHeight; 928 929 if (RenderView* renderView = this->renderView()) 930 renderView->setNeedsLayout(); 931} 932 933float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const 934{ 935 if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset) 936 return platformTopContentInset(); 937 938 if (!frame().isMainFrame()) 939 return 0; 940 941 Page* page = frame().page(); 942 return page ? page->topContentInset() : 0; 943} 944 945void FrameView::topContentInsetDidChange(float newTopContentInset) 946{ 947 RenderView* renderView = this->renderView(); 948 if (!renderView) 949 return; 950 951 if (platformWidget()) 952 platformSetTopContentInset(newTopContentInset); 953 954 layout(); 955 956 updateScrollbars(scrollOffset()); 957 if (renderView->usesCompositing()) 958 renderView->compositor().frameViewDidChangeSize(); 959 960 if (TiledBacking* tiledBacking = this->tiledBacking()) 961 tiledBacking->setTopContentInset(newTopContentInset); 962} 963 964bool FrameView::hasCompositedContent() const 965{ 966 if (RenderView* renderView = this->renderView()) 967 return renderView->compositor().inCompositingMode(); 968 return false; 969} 970 971bool FrameView::hasCompositedContentIncludingDescendants() const 972{ 973 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 974 RenderView* renderView = frame->contentRenderer(); 975 if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : 0) { 976 if (compositor->inCompositingMode()) 977 return true; 978 979 if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) 980 break; 981 } 982 } 983 return false; 984} 985 986bool FrameView::hasCompositingAncestor() const 987{ 988 for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) { 989 if (FrameView* view = frame->view()) { 990 if (view->hasCompositedContent()) 991 return true; 992 } 993 } 994 return false; 995} 996 997// Sometimes (for plug-ins) we need to eagerly go into compositing mode. 998void FrameView::enterCompositingMode() 999{ 1000 if (RenderView* renderView = this->renderView()) { 1001 renderView->compositor().enableCompositingMode(); 1002 if (!needsLayout()) 1003 renderView->compositor().scheduleCompositingLayerUpdate(); 1004 } 1005} 1006 1007bool FrameView::isEnclosedInCompositingLayer() const 1008{ 1009 auto frameOwnerRenderer = frame().ownerRenderer(); 1010 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint()) 1011 return true; 1012 1013 if (FrameView* parentView = parentFrameView()) 1014 return parentView->isEnclosedInCompositingLayer(); 1015 return false; 1016} 1017 1018bool FrameView::flushCompositingStateIncludingSubframes() 1019{ 1020 bool allFramesFlushed = flushCompositingStateForThisFrame(&frame()); 1021 1022 for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) { 1023 bool flushed = child->view()->flushCompositingStateForThisFrame(&frame()); 1024 allFramesFlushed &= flushed; 1025 } 1026 return allFramesFlushed; 1027} 1028 1029bool FrameView::isSoftwareRenderable() const 1030{ 1031 RenderView* renderView = this->renderView(); 1032 return !renderView || !renderView->compositor().has3DContent(); 1033} 1034 1035void FrameView::setIsInWindow(bool isInWindow) 1036{ 1037 if (RenderView* renderView = this->renderView()) 1038 renderView->setIsInWindow(isInWindow); 1039} 1040 1041RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const 1042{ 1043 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; 1044} 1045 1046inline void FrameView::forceLayoutParentViewIfNeeded() 1047{ 1048 RenderWidget* ownerRenderer = frame().ownerRenderer(); 1049 if (!ownerRenderer) 1050 return; 1051 1052 RenderBox* contentBox = embeddedContentBox(); 1053 if (!contentBox) 1054 return; 1055 1056 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox); 1057 if (svgRoot->everHadLayout() && !svgRoot->needsLayout()) 1058 return; 1059 1060 // If the embedded SVG document appears the first time, the ownerRenderer has already finished 1061 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced 1062 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before 1063 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its 1064 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the 1065 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying 1066 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>). 1067 Ref<FrameView> frameView(ownerRenderer->view().frameView()); 1068 1069 // Mark the owner renderer as needing layout. 1070 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc(); 1071 1072 // Synchronously enter layout, to layout the view containing the host object/embed/iframe. 1073 frameView->layout(); 1074} 1075 1076void FrameView::layout(bool allowSubtree) 1077{ 1078 if (isInLayout()) 1079 return; 1080 1081 // Protect the view from being deleted during layout (in recalcStyle). 1082 Ref<FrameView> protect(*this); 1083 1084 // Many of the tasks performed during layout can cause this function to be re-entered, 1085 // so save the layout phase now and restore it on exit. 1086 TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout); 1087 1088 // Every scroll that happens during layout is programmatic. 1089 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); 1090 1091 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening(); 1092 1093 if (inChildFrameLayoutWithFrameFlattening) { 1094 startLayoutAtMainFrameViewIfNeeded(allowSubtree); 1095 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView(); 1096 if (!root || !root->needsLayout()) 1097 return; 1098 } 1099 1100#if PLATFORM(IOS) 1101 if (updateFixedPositionLayoutRect()) 1102 allowSubtree = false; 1103#endif 1104 1105 m_layoutTimer.stop(); 1106 m_delayedLayout = false; 1107 m_setNeedsLayoutWasDeferred = false; 1108 1109 // we shouldn't enter layout() while painting 1110 ASSERT(!isPainting()); 1111 if (isPainting()) 1112 return; 1113 1114 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(&frame()); 1115 1116 if (!allowSubtree && m_layoutRoot) { 1117 m_layoutRoot->markContainingBlocksForLayout(false); 1118 m_layoutRoot = 0; 1119 } 1120 1121 ASSERT(frame().view() == this); 1122 ASSERT(frame().document()); 1123 1124 Document& document = *frame().document(); 1125 ASSERT(!document.inPageCache()); 1126 1127 bool subtree; 1128 RenderElement* root; 1129 1130 { 1131 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false); 1132 1133 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) { 1134 // This is a new top-level layout. If there are any remaining tasks from the previous 1135 // layout, finish them now. 1136 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true); 1137 performPostLayoutTasks(); 1138 } 1139 1140 m_layoutPhase = InPreLayoutStyleUpdate; 1141 1142 // Viewport-dependent media queries may cause us to need completely different style information. 1143 StyleResolver* styleResolver = document.styleResolverIfExists(); 1144 if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) { 1145 document.styleResolverChanged(DeferRecalcStyle); 1146 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds. 1147 InspectorInstrumentation::mediaQueryResultChanged(&document); 1148 } else 1149 document.evaluateMediaQueryList(); 1150 1151 // If there is any pagination to apply, it will affect the RenderView's style, so we should 1152 // take care of that now. 1153 applyPaginationToViewport(); 1154 1155 // Always ensure our style info is up-to-date. This can happen in situations where 1156 // the layout beats any sort of style recalc update that needs to occur. 1157 document.updateStyleIfNeeded(); 1158 m_layoutPhase = InPreLayout; 1159 1160 subtree = m_layoutRoot; 1161 1162 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 1163 // so there's no point to continuing to layout 1164 if (hasOneRef()) 1165 return; 1166 1167 root = subtree ? m_layoutRoot : document.renderView(); 1168 if (!root) { 1169 // FIXME: Do we need to set m_size here? 1170 return; 1171 } 1172 1173 // Close block here so we can set up the font cache purge preventer, which we will still 1174 // want in scope even after we want m_layoutSchedulingEnabled to be restored again. 1175 // The next block sets m_layoutSchedulingEnabled back to false once again. 1176 } 1177 1178 FontCachePurgePreventer fontCachePurgePreventer; 1179 RenderLayer* layer; 1180 1181 ++m_nestedLayoutCount; 1182 1183 { 1184 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false); 1185 1186 if (!m_layoutRoot) { 1187 HTMLElement* body = document.body(); 1188 if (body && body->renderer()) { 1189 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { 1190 body->renderer()->setChildNeedsLayout(); 1191 } else if (body->hasTagName(bodyTag)) { 1192 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport()) 1193 body->renderer()->setChildNeedsLayout(); 1194 } 1195 } 1196 1197#ifdef INSTRUMENT_LAYOUT_SCHEDULING 1198 if (m_firstLayout && !frame().ownerElement()) 1199 printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count()); 1200#endif 1201 } 1202 1203 autoSizeIfEnabled(); 1204 1205 m_needsFullRepaint = !subtree && (m_firstLayout || toRenderView(*root).printing()); 1206 1207 if (!subtree) { 1208 ScrollbarMode hMode; 1209 ScrollbarMode vMode; 1210 calculateScrollbarModesForLayout(hMode, vMode); 1211 1212 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) { 1213 if (m_firstLayout) { 1214 setScrollbarsSuppressed(true); 1215 1216 m_firstLayout = false; 1217 m_firstLayoutCallbackPending = true; 1218 m_lastViewportSize = sizeForResizeEvent(); 1219 m_lastZoomFactor = root->style().zoom(); 1220 1221 // Set the initial vMode to AlwaysOn if we're auto. 1222 if (vMode == ScrollbarAuto) 1223 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear. 1224 // Set the initial hMode to AlwaysOff if we're auto. 1225 if (hMode == ScrollbarAuto) 1226 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear. 1227 1228 setScrollbarModes(hMode, vMode); 1229 setScrollbarsSuppressed(false, true); 1230 } else 1231 setScrollbarModes(hMode, vMode); 1232 } 1233 1234 LayoutSize oldSize = m_size; 1235 1236 m_size = layoutSize(); 1237 1238 if (oldSize != m_size) { 1239 m_needsFullRepaint = true; 1240 if (!m_firstLayout) { 1241 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : 0; 1242 RenderBox* bodyRenderer = rootRenderer && document.body() ? document.body()->renderBox() : 0; 1243 if (bodyRenderer && bodyRenderer->stretchesToViewport()) 1244 bodyRenderer->setChildNeedsLayout(); 1245 else if (rootRenderer && rootRenderer->stretchesToViewport()) 1246 rootRenderer->setChildNeedsLayout(); 1247 1248 document.updateViewportUnitsOnResize(); 1249 } 1250 } 1251 1252 m_layoutPhase = InPreLayout; 1253 } 1254 1255 layer = root->enclosingLayer(); 1256 1257 bool disableLayoutState = false; 1258 if (subtree) { 1259 disableLayoutState = root->view().shouldDisableLayoutStateForSubtree(root); 1260 root->view().pushLayoutState(*root); 1261 } 1262 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? &root->view() : 0); 1263 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view()); 1264 1265 ASSERT(m_layoutPhase == InPreLayout); 1266 m_layoutPhase = InLayout; 1267 1268 forceLayoutParentViewIfNeeded(); 1269 1270 ASSERT(m_layoutPhase == InLayout); 1271 1272 root->layout(); 1273#if ENABLE(IOS_TEXT_AUTOSIZING) 1274 float minZoomFontSize = frame().settings().minimumZoomFontSize(); 1275 float visWidth = frame().page()->textAutosizingWidth(); 1276 if (minZoomFontSize && visWidth && !root->view().printing()) { 1277 root->adjustComputedFontSizesOnBlocks(minZoomFontSize, visWidth); 1278 bool needsLayout = root->needsLayout(); 1279 if (needsLayout) 1280 root->layout(); 1281 } 1282#endif 1283#if ENABLE(TEXT_AUTOSIZING) 1284 if (document.textAutosizer()->processSubtree(root) && root->needsLayout()) 1285 root->layout(); 1286#endif 1287 1288 ASSERT(m_layoutPhase == InLayout); 1289 1290 if (subtree) 1291 root->view().popLayoutState(*root); 1292 1293 m_layoutRoot = 0; 1294 1295 // Close block here to end the scope of changeSchedulingEnabled and layoutStateDisabler. 1296 } 1297 1298 m_layoutPhase = InViewSizeAdjust; 1299 1300 bool neededFullRepaint = m_needsFullRepaint; 1301 1302 if (!subtree && !toRenderView(*root).printing()) 1303 adjustViewSize(); 1304 1305 m_layoutPhase = InPostLayout; 1306 1307 m_needsFullRepaint = neededFullRepaint; 1308 1309 // Now update the positions of all layers. 1310 if (m_needsFullRepaint) 1311 root->view().repaintRootContents(); 1312 1313 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint)); 1314 1315 updateCompositingLayersAfterLayout(); 1316 1317 m_layoutCount++; 1318 1319#if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL) 1320 if (AXObjectCache* cache = root->document().existingAXObjectCache()) 1321 cache->postNotification(root, AXObjectCache::AXLayoutComplete); 1322#endif 1323 1324#if ENABLE(DASHBOARD_SUPPORT) 1325 updateAnnotatedRegions(); 1326#endif 1327 1328#if ENABLE(IOS_TOUCH_EVENTS) 1329 document.dirtyTouchEventRects(); 1330#endif 1331 1332 ASSERT(!root->needsLayout()); 1333 1334 updateCanBlitOnScrollRecursively(); 1335 1336 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) 1337 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight()); 1338 1339 if (!m_postLayoutTasksTimer.isActive()) { 1340 if (!m_inSynchronousPostLayout) { 1341 if (inChildFrameLayoutWithFrameFlattening) 1342 updateWidgetPositions(); 1343 else { 1344 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true); 1345 performPostLayoutTasks(); // Calls resumeScheduledEvents(). 1346 } 1347 } 1348 1349 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) { 1350 // If we need layout or are already in a synchronous call to postLayoutTasks(), 1351 // defer widget updates and event dispatch until after we return. postLayoutTasks() 1352 // can make us need to update again, and we can get stuck in a nasty cycle unless 1353 // we call it through the timer here. 1354 m_postLayoutTasksTimer.startOneShot(0); 1355 if (needsLayout()) 1356 layout(); 1357 } 1358 } 1359 1360 InspectorInstrumentation::didLayout(cookie, root); 1361 1362 --m_nestedLayoutCount; 1363} 1364 1365RenderBox* FrameView::embeddedContentBox() const 1366{ 1367 RenderView* renderView = this->renderView(); 1368 if (!renderView) 1369 return nullptr; 1370 1371 RenderObject* firstChild = renderView->firstChild(); 1372 if (!firstChild || !firstChild->isBox()) 1373 return nullptr; 1374 1375 // Curently only embedded SVG documents participate in the size-negotiation logic. 1376 if (toRenderBox(firstChild)->isSVGRoot()) 1377 return toRenderBox(firstChild); 1378 1379 return nullptr; 1380} 1381 1382void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject) 1383{ 1384 if (!m_embeddedObjectsToUpdate) 1385 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>(); 1386 1387 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement(); 1388 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) { 1389 // Tell the DOM element that it needs a widget update. 1390 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element); 1391 if (!pluginElement.needsCheckForSizeChange()) 1392 pluginElement.setNeedsWidgetUpdate(true); 1393 } 1394 1395 m_embeddedObjectsToUpdate->add(&embeddedObject); 1396} 1397 1398void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject) 1399{ 1400 if (!m_embeddedObjectsToUpdate) 1401 return; 1402 1403 m_embeddedObjectsToUpdate->remove(&embeddedObject); 1404} 1405 1406void FrameView::setMediaType(const String& mediaType) 1407{ 1408 m_mediaType = mediaType; 1409} 1410 1411String FrameView::mediaType() const 1412{ 1413 // See if we have an override type. 1414 String overrideType = frame().loader().client().overrideMediaType(); 1415 InspectorInstrumentation::applyEmulatedMedia(&frame(), &overrideType); 1416 if (!overrideType.isNull()) 1417 return overrideType; 1418 return m_mediaType; 1419} 1420 1421void FrameView::adjustMediaTypeForPrinting(bool printing) 1422{ 1423 if (printing) { 1424 if (m_mediaTypeWhenNotPrinting.isNull()) 1425 m_mediaTypeWhenNotPrinting = mediaType(); 1426 setMediaType("print"); 1427 } else { 1428 if (!m_mediaTypeWhenNotPrinting.isNull()) 1429 setMediaType(m_mediaTypeWhenNotPrinting); 1430 m_mediaTypeWhenNotPrinting = String(); 1431 } 1432} 1433 1434bool FrameView::useSlowRepaints(bool considerOverlap) const 1435{ 1436 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects()); 1437 1438 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints == 1439 // m_contentIsOpaque, so don't take the fast path for composited layers 1440 // if they are a platform widget in order to get painting correctness 1441 // for transparent layers. See the comment in WidgetMac::paint. 1442 if (contentsInCompositedLayer() && !platformWidget()) 1443 return mustBeSlow; 1444 1445 bool isOverlapped = m_isOverlapped && considerOverlap; 1446 1447 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque) 1448 return true; 1449 1450 if (FrameView* parentView = parentFrameView()) 1451 return parentView->useSlowRepaints(considerOverlap); 1452 1453 return false; 1454} 1455 1456bool FrameView::useSlowRepaintsIfNotOverlapped() const 1457{ 1458 return useSlowRepaints(false); 1459} 1460 1461void FrameView::updateCanBlitOnScrollRecursively() 1462{ 1463 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 1464 if (FrameView* view = frame->view()) 1465 view->setCanBlitOnScroll(!view->useSlowRepaints()); 1466 } 1467} 1468 1469bool FrameView::contentsInCompositedLayer() const 1470{ 1471 RenderView* renderView = this->renderView(); 1472 if (renderView && renderView->isComposited()) { 1473 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer(); 1474 if (layer && layer->drawsContent()) 1475 return true; 1476 } 1477 1478 return false; 1479} 1480 1481void FrameView::setCannotBlitToWindow() 1482{ 1483 m_cannotBlitToWindow = true; 1484 updateCanBlitOnScrollRecursively(); 1485} 1486 1487void FrameView::addSlowRepaintObject(RenderElement* o) 1488{ 1489 bool hadSlowRepaintObjects = hasSlowRepaintObjects(); 1490 1491 if (!m_slowRepaintObjects) 1492 m_slowRepaintObjects = std::make_unique<HashSet<RenderElement*>>(); 1493 1494 m_slowRepaintObjects->add(o); 1495 1496 if (!hadSlowRepaintObjects) { 1497 updateCanBlitOnScrollRecursively(); 1498 1499 if (Page* page = frame().page()) { 1500 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1501 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this); 1502 } 1503 } 1504} 1505 1506void FrameView::removeSlowRepaintObject(RenderElement* o) 1507{ 1508 if (!m_slowRepaintObjects) 1509 return; 1510 1511 m_slowRepaintObjects->remove(o); 1512 if (m_slowRepaintObjects->isEmpty()) { 1513 m_slowRepaintObjects = nullptr; 1514 updateCanBlitOnScrollRecursively(); 1515 1516 if (Page* page = frame().page()) { 1517 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1518 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this); 1519 } 1520 } 1521} 1522 1523void FrameView::addViewportConstrainedObject(RenderElement* object) 1524{ 1525 if (!m_viewportConstrainedObjects) 1526 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>(); 1527 1528 if (!m_viewportConstrainedObjects->contains(object)) { 1529 m_viewportConstrainedObjects->add(object); 1530 if (platformWidget()) 1531 updateCanBlitOnScrollRecursively(); 1532 1533 if (Page* page = frame().page()) { 1534 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1535 scrollingCoordinator->frameViewFixedObjectsDidChange(this); 1536 } 1537 } 1538} 1539 1540void FrameView::removeViewportConstrainedObject(RenderElement* object) 1541{ 1542 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) { 1543 if (Page* page = frame().page()) { 1544 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 1545 scrollingCoordinator->frameViewFixedObjectsDidChange(this); 1546 } 1547 1548 // FIXME: In addFixedObject() we only call this if there's a platform widget, 1549 // why isn't the same check being made here? 1550 updateCanBlitOnScrollRecursively(); 1551 } 1552} 1553 1554LayoutRect FrameView::viewportConstrainedVisibleContentRect() const 1555{ 1556#if PLATFORM(IOS) 1557 if (useCustomFixedPositionLayoutRect()) 1558 return customFixedPositionLayoutRect(); 1559#endif 1560 LayoutRect viewportRect = visibleContentRect(); 1561 1562 viewportRect.setLocation(toLayoutPoint(scrollOffsetForFixedPosition())); 1563 return viewportRect; 1564} 1565 1566LayoutSize FrameView::scrollOffsetForFixedPosition(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements behaviorForFixed, int headerHeight, int footerHeight) 1567{ 1568 LayoutPoint position; 1569 if (behaviorForFixed == StickToDocumentBounds) 1570 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight); 1571 else { 1572 position = scrollPosition; 1573 position.setY(position.y() - headerHeight); 1574 } 1575 1576 LayoutSize maxSize = totalContentsSize - visibleContentRect.size(); 1577 1578 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width(); 1579 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height(); 1580 1581 return LayoutSize(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor); 1582} 1583 1584LayoutSize FrameView::scrollOffsetForFixedPosition() const 1585{ 1586 IntRect visibleContentRect = this->visibleContentRect(); 1587 IntSize totalContentsSize = this->totalContentsSize(); 1588 IntPoint scrollPosition = this->scrollPosition(); 1589 IntPoint scrollOrigin = this->scrollOrigin(); 1590 float frameScaleFactor = frame().frameScaleFactor(); 1591 ScrollBehaviorForFixedElements behaviorForFixed = scrollBehaviorForFixedElements(); 1592 return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), behaviorForFixed, headerHeight(), footerHeight()); 1593} 1594 1595float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset) 1596{ 1597 if (!topContentInset) 1598 return 0; 1599 1600 // The insetClipLayer should not move for negative scroll values. 1601 float scrollY = std::max<float>(0, scrollPosition.y()); 1602 1603 if (scrollY >= topContentInset) 1604 return 0; 1605 1606 return topContentInset - scrollY; 1607} 1608 1609float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset) 1610{ 1611 if (!topContentInset) 1612 return 0; 1613 1614 float scrollY = std::max<float>(0, scrollPosition.y()); 1615 1616 if (scrollY >= topContentInset) 1617 return topContentInset; 1618 1619 return scrollY; 1620} 1621 1622float FrameView::yPositionForRootContentLayer(const FloatPoint& scrollPosition, float topContentInset, float headerHeight) 1623{ 1624 return yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight; 1625} 1626 1627float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight) 1628{ 1629 return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight; 1630} 1631 1632#if PLATFORM(IOS) 1633LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior) 1634{ 1635 if (fixedElementsLayoutRelativeToFrame) 1636 return visibleContentRect; 1637 1638 if (totalContentsSize.isEmpty()) 1639 return visibleContentRect; 1640 1641 // We impose an lower limit on the size (so an upper limit on the scale) of 1642 // the rect used to position fixed objects so that they don't crowd into the 1643 // center of the screen at larger scales. 1644 const LayoutUnit maxContentWidthForZoomThreshold = LayoutUnit::fromPixel(1024); 1645 float zoomedOutScale = frameScaleFactor * visibleContentRect.width() / std::min(maxContentWidthForZoomThreshold, totalContentsSize.width()); 1646 float constraintThresholdScale = 1.5 * zoomedOutScale; 1647 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale); 1648 1649 LayoutRect viewportConstrainedObjectsRect = visibleContentRect; 1650 1651 if (frameScaleFactor > constraintThresholdScale) { 1652 FloatRect contentRect(FloatPoint(), totalContentsSize); 1653 FloatRect viewportRect = visibleContentRect; 1654 1655 // Scale the rect up from a point that is relative to its position in the viewport. 1656 FloatSize sizeDelta = contentRect.size() - viewportRect.size(); 1657 1658 FloatPoint scaleOrigin; 1659 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0); 1660 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0); 1661 1662 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y()); 1663 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale); 1664 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y()); 1665 1666 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect)); 1667 } 1668 1669 if (scrollBehavior == StickToDocumentBounds) { 1670 LayoutRect documentBounds(LayoutPoint(), totalContentsSize); 1671 viewportConstrainedObjectsRect.intersect(documentBounds); 1672 } 1673 1674 return viewportConstrainedObjectsRect; 1675} 1676 1677LayoutRect FrameView::viewportConstrainedObjectsRect() const 1678{ 1679 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements()); 1680} 1681#endif 1682 1683IntPoint FrameView::minimumScrollPosition() const 1684{ 1685 IntPoint minimumPosition(ScrollView::minimumScrollPosition()); 1686 1687 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom) 1688 minimumPosition.setY(maximumScrollPosition().y()); 1689 1690 return minimumPosition; 1691} 1692 1693IntPoint FrameView::maximumScrollPosition() const 1694{ 1695 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y()); 1696 1697 maximumOffset.clampNegativeToZero(); 1698 1699 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop) 1700 maximumOffset.setY(minimumScrollPosition().y()); 1701 1702 return maximumOffset; 1703} 1704 1705void FrameView::delayedScrollEventTimerFired(Timer<FrameView>&) 1706{ 1707 sendScrollEvent(); 1708} 1709 1710bool FrameView::fixedElementsLayoutRelativeToFrame() const 1711{ 1712 return frame().settings().fixedElementsLayoutRelativeToFrame(); 1713} 1714 1715IntPoint FrameView::lastKnownMousePosition() const 1716{ 1717 return frame().eventHandler().lastKnownMousePosition(); 1718} 1719 1720bool FrameView::isHandlingWheelEvent() const 1721{ 1722 return frame().eventHandler().isHandlingWheelEvent(); 1723} 1724 1725bool FrameView::shouldSetCursor() const 1726{ 1727 Page* page = frame().page(); 1728 return page && page->isVisible() && page->focusController().isActive(); 1729} 1730 1731bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) 1732{ 1733 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) { 1734 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect); 1735 return true; 1736 } 1737 1738 const bool isCompositedContentLayer = contentsInCompositedLayer(); 1739 1740 // Get the rects of the fixed objects visible in the rectToScroll 1741 Region regionToUpdate; 1742 for (auto& renderer : *m_viewportConstrainedObjects) { 1743 if (!renderer->style().hasViewportConstrainedPosition()) 1744 continue; 1745 if (renderer->isComposited()) 1746 continue; 1747 1748 // Fixed items should always have layers. 1749 ASSERT(renderer->hasLayer()); 1750 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); 1751 1752 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView 1753 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) { 1754 // Don't invalidate for invisible fixed layers. 1755 continue; 1756 } 1757 1758#if ENABLE(CSS_FILTERS) 1759 if (layer->hasAncestorWithFilterOutsets()) { 1760 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot 1761 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page. 1762 return false; 1763 } 1764#endif 1765 IntRect updateRect = pixelSnappedIntRect(layer->repaintRectIncludingNonCompositingDescendants()); 1766 updateRect = contentsToRootView(updateRect); 1767 if (!isCompositedContentLayer && clipsRepaints()) 1768 updateRect.intersect(rectToScroll); 1769 if (!updateRect.isEmpty()) 1770 regionToUpdate.unite(updateRect); 1771 } 1772 1773 // 1) scroll 1774 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect); 1775 1776 // 2) update the area of fixed objects that has been invalidated 1777 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects(); 1778 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size(); 1779 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) { 1780 IntRect updateRect = subRectsToUpdate[i]; 1781 IntRect scrolledRect = updateRect; 1782 scrolledRect.move(scrollDelta); 1783 updateRect.unite(scrolledRect); 1784 if (isCompositedContentLayer) { 1785 updateRect = rootViewToContents(updateRect); 1786 ASSERT(renderView()); 1787 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect); 1788 continue; 1789 } 1790 if (clipsRepaints()) 1791 updateRect.intersect(rectToScroll); 1792 hostWindow()->invalidateContentsAndRootView(updateRect); 1793 } 1794 1795 return true; 1796} 1797 1798void FrameView::scrollContentsSlowPath(const IntRect& updateRect) 1799{ 1800 if (contentsInCompositedLayer()) { 1801 // FIXME: respect paintsEntireContents()? 1802 IntRect updateRect = visibleContentRect(LegacyIOSDocumentVisibleRect); 1803 1804 // Make sure to "apply" the scale factor here since we're converting from frame view 1805 // coordinates to layer backing coordinates. 1806 updateRect.scale(1 / frame().frameScaleFactor()); 1807 1808 ASSERT(renderView()); 1809 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect, GraphicsLayer::DoNotClipToLayer); 1810 } 1811 1812 repaintSlowRepaintObjects(); 1813 1814 if (RenderWidget* frameRenderer = frame().ownerRenderer()) { 1815 if (isEnclosedInCompositingLayer()) { 1816 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), 1817 frameRenderer->borderTop() + frameRenderer->paddingTop(), 1818 visibleWidth(), visibleHeight()); 1819 frameRenderer->repaintRectangle(rect); 1820 return; 1821 } 1822 } 1823 1824 ScrollView::scrollContentsSlowPath(updateRect); 1825} 1826 1827void FrameView::repaintSlowRepaintObjects() 1828{ 1829 if (!m_slowRepaintObjects) 1830 return; 1831 1832 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly 1833 // repaint them after scrolling. 1834 for (auto& renderer : *m_slowRepaintObjects) 1835 renderer->repaintSlowRepaintObject(); 1836} 1837 1838// Note that this gets called at painting time. 1839void FrameView::setIsOverlapped(bool isOverlapped) 1840{ 1841 if (isOverlapped == m_isOverlapped) 1842 return; 1843 1844 m_isOverlapped = isOverlapped; 1845 updateCanBlitOnScrollRecursively(); 1846 1847 if (hasCompositedContentIncludingDescendants()) { 1848 // Overlap can affect compositing tests, so if it changes, we need to trigger 1849 // a layer update in the parent document. 1850 if (Frame* parentFrame = frame().tree().parent()) { 1851 if (RenderView* parentView = parentFrame->contentRenderer()) { 1852 RenderLayerCompositor& compositor = parentView->compositor(); 1853 compositor.setCompositingLayersNeedRebuild(); 1854 compositor.scheduleCompositingLayerUpdate(); 1855 } 1856 } 1857 1858 if (RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) { 1859 // We also need to trigger reevaluation for this and all descendant frames, 1860 // since a frame uses compositing if any ancestor is compositing. 1861 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 1862 if (RenderView* view = frame->contentRenderer()) { 1863 RenderLayerCompositor& compositor = view->compositor(); 1864 compositor.setCompositingLayersNeedRebuild(); 1865 compositor.scheduleCompositingLayerUpdate(); 1866 } 1867 } 1868 } 1869 } 1870} 1871 1872bool FrameView::isOverlappedIncludingAncestors() const 1873{ 1874 if (isOverlapped()) 1875 return true; 1876 1877 if (FrameView* parentView = parentFrameView()) { 1878 if (parentView->isOverlapped()) 1879 return true; 1880 } 1881 1882 return false; 1883} 1884 1885void FrameView::setContentIsOpaque(bool contentIsOpaque) 1886{ 1887 if (contentIsOpaque == m_contentIsOpaque) 1888 return; 1889 1890 m_contentIsOpaque = contentIsOpaque; 1891 updateCanBlitOnScrollRecursively(); 1892} 1893 1894void FrameView::restoreScrollbar() 1895{ 1896 setScrollbarsSuppressed(false); 1897} 1898 1899bool FrameView::scrollToFragment(const URL& url) 1900{ 1901 // If our URL has no ref, then we have no place we need to jump to. 1902 // OTOH If CSS target was set previously, we want to set it to 0, recalc 1903 // and possibly repaint because :target pseudo class may have been 1904 // set (see bug 11321). 1905 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget()) 1906 return false; 1907 1908 String fragmentIdentifier = url.fragmentIdentifier(); 1909 if (scrollToAnchor(fragmentIdentifier)) 1910 return true; 1911 1912 // Try again after decoding the ref, based on the document's encoding. 1913 if (TextResourceDecoder* decoder = frame().document()->decoder()) 1914 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding())); 1915 1916 return false; 1917} 1918 1919bool FrameView::scrollToAnchor(const String& name) 1920{ 1921 ASSERT(frame().document()); 1922 1923 if (!frame().document()->haveStylesheetsLoaded()) { 1924 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(true); 1925 return false; 1926 } 1927 1928 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(false); 1929 1930 Element* anchorElement = frame().document()->findAnchor(name); 1931 1932 // Setting to null will clear the current target. 1933 frame().document()->setCSSTarget(anchorElement); 1934 1935 if (frame().document()->isSVGDocument()) { 1936 if (SVGSVGElement* svg = toSVGDocument(frame().document())->rootElement()) { 1937 svg->setupInitialView(name, anchorElement); 1938 if (!anchorElement) 1939 return true; 1940 } 1941 } 1942 1943 // Implement the rule that "" and "top" both mean top of page as in other browsers. 1944 if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top"))) 1945 return false; 1946 1947 maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : frame().document()); 1948 1949 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation. 1950 if (anchorElement && anchorElement->isFocusable()) 1951 frame().document()->setFocusedElement(anchorElement); 1952 1953 return true; 1954} 1955 1956void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) 1957{ 1958 m_maintainScrollPositionAnchor = anchorNode; 1959 if (!m_maintainScrollPositionAnchor) 1960 return; 1961 1962 // We need to update the layout before scrolling, otherwise we could 1963 // really mess things up if an anchor scroll comes at a bad moment. 1964 frame().document()->updateStyleIfNeeded(); 1965 // Only do a layout if changes have occurred that make it necessary. 1966 RenderView* renderView = this->renderView(); 1967 if (renderView && renderView->needsLayout()) 1968 layout(); 1969 else 1970 scrollToAnchor(); 1971} 1972 1973void FrameView::scrollElementToRect(Element* element, const IntRect& rect) 1974{ 1975 frame().document()->updateLayoutIgnorePendingStylesheets(); 1976 1977 LayoutRect bounds = element->boundingBox(); 1978 int centeringOffsetX = (rect.width() - bounds.width()) / 2; 1979 int centeringOffsetY = (rect.height() - bounds.height()) / 2; 1980 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y())); 1981} 1982 1983void FrameView::setScrollPosition(const IntPoint& scrollPoint) 1984{ 1985 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); 1986 m_maintainScrollPositionAnchor = 0; 1987 ScrollView::setScrollPosition(scrollPoint); 1988} 1989 1990void FrameView::delegatesScrollingDidChange() 1991{ 1992 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor. 1993 if (hasCompositedContent()) 1994 clearBackingStores(); 1995} 1996 1997#if USE(TILED_BACKING_STORE) 1998void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect) 1999{ 2000 bool visibleContentSizeDidChange = false; 2001 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) { 2002 // When the viewport size changes or the content is scaled, we need to 2003 // reposition the fixed and sticky positioned elements. 2004 setViewportConstrainedObjectsNeedLayout(); 2005 visibleContentSizeDidChange = true; 2006 } 2007 2008 IntSize offset = scrollOffset(); 2009 IntPoint oldPosition = scrollPosition(); 2010 ScrollView::setFixedVisibleContentRect(visibleContentRect); 2011 if (offset != scrollOffset()) { 2012 updateLayerPositionsAfterScrolling(); 2013 if (frame().page()->settings().acceleratedCompositingForFixedPositionEnabled()) 2014 updateCompositingLayersAfterScrolling(); 2015 IntPoint newPosition = scrollPosition(); 2016 scrollAnimator()->setCurrentPosition(scrollPosition()); 2017 scrollPositionChanged(oldPosition, newPosition); 2018 } 2019 if (visibleContentSizeDidChange) { 2020 // Update the scroll-bars to calculate new page-step size. 2021 updateScrollbars(scrollOffset()); 2022 } 2023 frame().loader().client().didChangeScrollOffset(); 2024} 2025#endif 2026 2027void FrameView::setViewportConstrainedObjectsNeedLayout() 2028{ 2029 if (!hasViewportConstrainedObjects()) 2030 return; 2031 2032 for (auto& renderer : *m_viewportConstrainedObjects) 2033 renderer->setNeedsLayout(); 2034} 2035 2036void FrameView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition) 2037{ 2038 updateLayerPositionsAfterScrolling(); 2039 updateCompositingLayersAfterScrolling(); 2040 repaintSlowRepaintObjects(); 2041 scrollPositionChanged(oldPosition, newPosition); 2042} 2043 2044void FrameView::scrollPositionChanged(const IntPoint& oldPosition, const IntPoint& newPosition) 2045{ 2046 std::chrono::milliseconds throttlingDelay = frame().page()->chrome().client().eventThrottlingDelay(); 2047 2048 if (throttlingDelay == std::chrono::milliseconds::zero()) { 2049 m_delayedScrollEventTimer.stop(); 2050 sendScrollEvent(); 2051 } else if (!m_delayedScrollEventTimer.isActive()) 2052 m_delayedScrollEventTimer.startOneShot(throttlingDelay); 2053 2054 if (Document* document = frame().document()) 2055 document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize()); 2056 2057 if (RenderView* renderView = this->renderView()) { 2058 if (renderView->usesCompositing()) 2059 renderView->compositor().frameViewDidScroll(); 2060 } 2061 2062 resumeVisibleImageAnimationsIncludingSubframes(); 2063} 2064 2065void FrameView::resumeVisibleImageAnimationsIncludingSubframes() 2066{ 2067 // A change in scroll position may affect image visibility in subframes. 2068 for (auto* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 2069 if (auto* renderView = frame->contentRenderer()) 2070 renderView->resumePausedImageAnimationsIfNeeded(); 2071 } 2072} 2073 2074void FrameView::updateLayerPositionsAfterScrolling() 2075{ 2076 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway. 2077 if (m_layoutPhase == InViewSizeAdjust) 2078 return; 2079 2080 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { 2081 if (RenderView* renderView = this->renderView()) { 2082 updateWidgetPositions(); 2083 renderView->layer()->updateLayerPositionsAfterDocumentScroll(); 2084 } 2085 } 2086} 2087 2088bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const 2089{ 2090#if ENABLE(ASYNC_SCROLLING) 2091 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well. 2092 2093 Page* page = frame().page(); 2094 if (!page) 2095 return true; 2096 2097 if (&page->mainFrame() != &frame()) 2098 return true; 2099 2100 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator(); 2101 if (!scrollingCoordinator) 2102 return true; 2103 2104 if (!scrollingCoordinator->supportsFixedPositionLayers()) 2105 return true; 2106 2107 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously()) 2108 return true; 2109 2110 if (inProgrammaticScroll()) 2111 return true; 2112 2113 return false; 2114#endif 2115 return true; 2116} 2117 2118void FrameView::updateCompositingLayersAfterScrolling() 2119{ 2120 if (!shouldUpdateCompositingLayersAfterScrolling()) 2121 return; 2122 2123 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { 2124 if (RenderView* renderView = this->renderView()) 2125 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll); 2126 } 2127} 2128 2129bool FrameView::isRubberBandInProgress() const 2130{ 2131 if (scrollbarsSuppressed()) 2132 return false; 2133 2134 // If the scrolling thread updates the scroll position for this FrameView, then we should return 2135 // ScrollingCoordinator::isRubberBandInProgress(). 2136 if (Page* page = frame().page()) { 2137 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { 2138 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously()) 2139 return scrollingCoordinator->isRubberBandInProgress(); 2140 } 2141 } 2142 2143 // If the main thread updates the scroll position for this FrameView, we should return 2144 // ScrollAnimator::isRubberBandInProgress(). 2145 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) 2146 return scrollAnimator->isRubberBandInProgress(); 2147 2148 return false; 2149} 2150 2151bool FrameView::requestScrollPositionUpdate(const IntPoint& position) 2152{ 2153#if ENABLE(ASYNC_SCROLLING) 2154 if (TiledBacking* tiledBacking = this->tiledBacking()) 2155 tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size())); 2156 2157 if (Page* page = frame().page()) { 2158 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 2159 return scrollingCoordinator->requestScrollPositionUpdate(this, position); 2160 } 2161#else 2162 UNUSED_PARAM(position); 2163#endif 2164 2165 return false; 2166} 2167 2168HostWindow* FrameView::hostWindow() const 2169{ 2170 if (Page* page = frame().page()) 2171 return &page->chrome(); 2172 return 0; 2173} 2174 2175void FrameView::addTrackedRepaintRect(const FloatRect& r) 2176{ 2177 if (!m_isTrackingRepaints || r.isEmpty()) 2178 return; 2179 2180 FloatRect repaintRect = r; 2181 repaintRect.move(-scrollOffset()); 2182 m_trackedRepaintRects.append(repaintRect); 2183} 2184 2185void FrameView::repaintContentRectangle(const IntRect& r) 2186{ 2187 ASSERT(!frame().ownerElement()); 2188 2189 if (!shouldUpdate()) 2190 return; 2191 2192 ScrollView::repaintContentRectangle(r); 2193} 2194 2195static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderObject& renderer, unsigned countSoFar, unsigned threshold) 2196{ 2197 // FIXME: Consider writing this using RenderObject::nextInPreOrder() instead of using recursion. 2198 if (renderer.isText()) 2199 countSoFar += toRenderText(renderer).text()->length(); 2200 2201 for (RenderObject* child = renderer.firstChildSlow(); child; child = child->nextSibling()) { 2202 if (countSoFar >= threshold) 2203 break; 2204 countSoFar = countRenderedCharactersInRenderObjectWithThreshold(*child, countSoFar, threshold); 2205 } 2206 return countSoFar; 2207} 2208 2209bool FrameView::renderedCharactersExceed(unsigned threshold) 2210{ 2211 if (!m_frame->contentRenderer()) 2212 return false; 2213 return countRenderedCharactersInRenderObjectWithThreshold(*m_frame->contentRenderer(), 0, threshold) >= threshold; 2214} 2215 2216void FrameView::contentsResized() 2217{ 2218 ScrollView::contentsResized(); 2219 setNeedsLayout(); 2220} 2221 2222void FrameView::fixedLayoutSizeChanged() 2223{ 2224 // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized(). 2225 // An ASSERT is triggered when a view schedules a layout before being attached to a frame. 2226 if (!frame().view()) 2227 return; 2228 ScrollView::fixedLayoutSizeChanged(); 2229} 2230 2231bool FrameView::shouldLayoutAfterContentsResized() const 2232{ 2233 return !useFixedLayout() || useCustomFixedPositionLayoutRect(); 2234} 2235 2236void FrameView::visibleContentsResized() 2237{ 2238 // We check to make sure the view is attached to a frame() as this method can 2239 // be triggered before the view is attached by Frame::createView(...) setting 2240 // various values such as setScrollBarModes(...) for example. An ASSERT is 2241 // triggered when a view is layout before being attached to a frame(). 2242 if (!frame().view()) 2243 return; 2244 2245#if PLATFORM(IOS) 2246 if (RenderView* root = m_frame->contentRenderer()) { 2247 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) { 2248 setViewportConstrainedObjectsNeedLayout(); 2249 // We must eagerly enter compositing mode because fixed position elements 2250 // will not have been made compositing via a preceding style change before 2251 // m_useCustomFixedPositionLayoutRect was true. 2252 root->compositor().enableCompositingMode(); 2253 } 2254 } 2255#endif 2256 2257 if (shouldLayoutAfterContentsResized() && needsLayout()) 2258 layout(); 2259 2260 if (RenderView* renderView = this->renderView()) { 2261 if (renderView->usesCompositing()) 2262 renderView->compositor().frameViewDidChangeSize(); 2263 } 2264} 2265 2266void FrameView::addedOrRemovedScrollbar() 2267{ 2268 if (RenderView* renderView = this->renderView()) { 2269 if (renderView->usesCompositing()) 2270 renderView->compositor().frameViewDidAddOrRemoveScrollbars(); 2271 } 2272} 2273 2274static LayerFlushThrottleState::Flags determineLayerFlushThrottleState(Page& page) 2275{ 2276 // We only throttle when constantly receiving new data during the inital page load. 2277 if (!page.progress().isMainLoadProgressing()) 2278 return 0; 2279 // Scrolling during page loading disables throttling. 2280 if (page.mainFrame().view()->wasScrolledByUser()) 2281 return 0; 2282 // Disable for image documents so large GIF animations don't get throttled during loading. 2283 auto* document = page.mainFrame().document(); 2284 if (!document || isImageDocument(*document)) 2285 return 0; 2286 return LayerFlushThrottleState::Enabled; 2287} 2288 2289void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction() 2290{ 2291 if (!frame().page()) 2292 return; 2293 auto& page = *frame().page(); 2294 2295 LayerFlushThrottleState::Flags flags = LayerFlushThrottleState::UserIsInteracting | determineLayerFlushThrottleState(page); 2296 if (page.chrome().client().adjustLayerFlushThrottling(flags)) 2297 return; 2298 2299 if (RenderView* view = renderView()) 2300 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction(); 2301} 2302 2303void FrameView::loadProgressingStatusChanged() 2304{ 2305 updateLayerFlushThrottling(); 2306 adjustTiledBackingCoverage(); 2307} 2308 2309void FrameView::updateLayerFlushThrottling() 2310{ 2311 ASSERT(frame().isMainFrame()); 2312 auto& page = *frame().page(); 2313 2314 LayerFlushThrottleState::Flags flags = determineLayerFlushThrottleState(page); 2315 2316 // See if the client is handling throttling. 2317 if (page.chrome().client().adjustLayerFlushThrottling(flags)) 2318 return; 2319 2320 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 2321 if (RenderView* renderView = frame->contentRenderer()) 2322 renderView->compositor().setLayerFlushThrottlingEnabled(flags & LayerFlushThrottleState::Enabled); 2323 } 2324} 2325 2326void FrameView::adjustTiledBackingCoverage() 2327{ 2328 if (!m_speculativeTilingEnabled) 2329 enableSpeculativeTilingIfNeeded(); 2330 2331 RenderView* renderView = this->renderView(); 2332 if (renderView && renderView->layer()->backing()) 2333 renderView->layer()->backing()->adjustTiledBackingCoverage(); 2334#if PLATFORM(IOS) 2335 if (LegacyTileCache* tileCache = legacyTileCache()) 2336 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled); 2337#endif 2338} 2339 2340static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view) 2341{ 2342 return view.isVisuallyNonEmpty() && !view.frame().page()->progress().isMainLoadProgressing(); 2343} 2344 2345void FrameView::enableSpeculativeTilingIfNeeded() 2346{ 2347 ASSERT(!m_speculativeTilingEnabled); 2348 if (m_wasScrolledByUser) { 2349 m_speculativeTilingEnabled = true; 2350 return; 2351 } 2352 if (!shouldEnableSpeculativeTilingDuringLoading(*this)) 2353 return; 2354 if (m_speculativeTilingEnableTimer.isActive()) 2355 return; 2356 // Delay enabling a bit as load completion may trigger further loading from scripts. 2357 static const double speculativeTilingEnableDelay = 0.5; 2358 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay); 2359} 2360 2361void FrameView::speculativeTilingEnableTimerFired(Timer<FrameView>&) 2362{ 2363 if (m_speculativeTilingEnabled) 2364 return; 2365 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this); 2366 adjustTiledBackingCoverage(); 2367} 2368 2369void FrameView::layoutTimerFired(Timer<FrameView>&) 2370{ 2371#ifdef INSTRUMENT_LAYOUT_SCHEDULING 2372 if (!frame().document()->ownerElement()) 2373 printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count()); 2374#endif 2375 layout(); 2376} 2377 2378void FrameView::scheduleRelayout() 2379{ 2380 // FIXME: We should assert the page is not in the page cache, but that is causing 2381 // too many false assertions. See <rdar://problem/7218118>. 2382 ASSERT(frame().view() == this); 2383 2384 if (m_layoutRoot) { 2385 m_layoutRoot->markContainingBlocksForLayout(false); 2386 m_layoutRoot = 0; 2387 } 2388 if (!m_layoutSchedulingEnabled) 2389 return; 2390 if (!needsLayout()) 2391 return; 2392 if (!frame().document()->shouldScheduleLayout()) 2393 return; 2394 InspectorInstrumentation::didInvalidateLayout(&frame()); 2395 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames. 2396 // Also invalidate parent frame starting from the owner element of this frame. 2397 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening()) 2398 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain); 2399 2400 std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay(); 2401 if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count()) 2402 unscheduleRelayout(); 2403 if (m_layoutTimer.isActive()) 2404 return; 2405 2406 m_delayedLayout = delay.count(); 2407 2408#ifdef INSTRUMENT_LAYOUT_SCHEDULING 2409 if (!frame().document()->ownerElement()) 2410 printf("Scheduling layout for %d\n", delay); 2411#endif 2412 2413 m_layoutTimer.startOneShot(delay); 2414} 2415 2416static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant) 2417{ 2418 for (RenderObject* r = descendant; r; r = r->container()) { 2419 if (r == ancestor) 2420 return true; 2421 } 2422 return false; 2423} 2424 2425void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot) 2426{ 2427 ASSERT(renderView()); 2428 RenderView& renderView = *this->renderView(); 2429 2430 // Try to catch unnecessary work during render tree teardown. 2431 ASSERT(!renderView.documentBeingDestroyed()); 2432 ASSERT(frame().view() == this); 2433 2434 if (renderView.needsLayout()) { 2435 newRelayoutRoot.markContainingBlocksForLayout(false); 2436 return; 2437 } 2438 2439 if (!layoutPending() && m_layoutSchedulingEnabled) { 2440 std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay(); 2441 ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout()); 2442 m_layoutRoot = &newRelayoutRoot; 2443 InspectorInstrumentation::didInvalidateLayout(&frame()); 2444 m_delayedLayout = delay.count(); 2445 m_layoutTimer.startOneShot(delay); 2446 return; 2447 } 2448 2449 if (m_layoutRoot == &newRelayoutRoot) 2450 return; 2451 2452 if (!m_layoutRoot) { 2453 // Just relayout the subtree. 2454 newRelayoutRoot.markContainingBlocksForLayout(false); 2455 InspectorInstrumentation::didInvalidateLayout(&frame()); 2456 return; 2457 } 2458 2459 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) { 2460 // Keep the current root. 2461 newRelayoutRoot.markContainingBlocksForLayout(false, m_layoutRoot); 2462 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); 2463 return; 2464 } 2465 2466 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) { 2467 // Re-root at newRelayoutRoot. 2468 m_layoutRoot->markContainingBlocksForLayout(false, &newRelayoutRoot); 2469 m_layoutRoot = &newRelayoutRoot; 2470 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); 2471 InspectorInstrumentation::didInvalidateLayout(&frame()); 2472 return; 2473 } 2474 2475 // Just do a full relayout. 2476 m_layoutRoot->markContainingBlocksForLayout(false); 2477 m_layoutRoot = 0; 2478 newRelayoutRoot.markContainingBlocksForLayout(false); 2479 InspectorInstrumentation::didInvalidateLayout(&frame()); 2480} 2481 2482bool FrameView::layoutPending() const 2483{ 2484 return m_layoutTimer.isActive(); 2485} 2486 2487bool FrameView::needsLayout() const 2488{ 2489 // This can return true in cases where the document does not have a body yet. 2490 // Document::shouldScheduleLayout takes care of preventing us from scheduling 2491 // layout in that case. 2492 RenderView* renderView = this->renderView(); 2493 return layoutPending() 2494 || (renderView && renderView->needsLayout()) 2495 || m_layoutRoot 2496 || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred); 2497} 2498 2499void FrameView::setNeedsLayout() 2500{ 2501 if (m_deferSetNeedsLayouts) { 2502 m_setNeedsLayoutWasDeferred = true; 2503 return; 2504 } 2505 2506 if (RenderView* renderView = this->renderView()) 2507 renderView->setNeedsLayout(); 2508} 2509 2510void FrameView::unscheduleRelayout() 2511{ 2512 if (!m_layoutTimer.isActive()) 2513 return; 2514 2515#ifdef INSTRUMENT_LAYOUT_SCHEDULING 2516 if (!frame().document()->ownerElement()) 2517 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime()); 2518#endif 2519 2520 m_layoutTimer.stop(); 2521 m_delayedLayout = false; 2522} 2523 2524#if ENABLE(REQUEST_ANIMATION_FRAME) 2525void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime) 2526{ 2527 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) { 2528 frame->view()->serviceScrollAnimations(); 2529 frame->animation().serviceAnimations(); 2530 } 2531 2532 Vector<RefPtr<Document>> documents; 2533 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) 2534 documents.append(frame->document()); 2535 2536 for (size_t i = 0; i < documents.size(); ++i) 2537 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime); 2538} 2539#endif 2540 2541bool FrameView::isTransparent() const 2542{ 2543 return m_isTransparent; 2544} 2545 2546void FrameView::setTransparent(bool isTransparent) 2547{ 2548 if (m_isTransparent == isTransparent) 2549 return; 2550 2551 m_isTransparent = isTransparent; 2552 2553 RenderView* renderView = this->renderView(); 2554 if (!renderView) 2555 return; 2556 2557 RenderLayerCompositor& compositor = renderView->compositor(); 2558 compositor.setCompositingLayersNeedRebuild(); 2559 compositor.scheduleCompositingLayerUpdate(); 2560} 2561 2562bool FrameView::hasOpaqueBackground() const 2563{ 2564 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha(); 2565} 2566 2567Color FrameView::baseBackgroundColor() const 2568{ 2569 return m_baseBackgroundColor; 2570} 2571 2572void FrameView::setBaseBackgroundColor(const Color& backgroundColor) 2573{ 2574 if (!backgroundColor.isValid()) 2575 m_baseBackgroundColor = Color::white; 2576 else 2577 m_baseBackgroundColor = backgroundColor; 2578 2579 recalculateScrollbarOverlayStyle(); 2580} 2581 2582void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent) 2583{ 2584 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 2585 if (FrameView* view = frame->view()) { 2586 view->setTransparent(transparent); 2587 view->setBaseBackgroundColor(backgroundColor); 2588 } 2589 } 2590} 2591 2592bool FrameView::hasExtendedBackgroundRectForPainting() const 2593{ 2594 if (!frame().settings().backgroundShouldExtendBeyondPage()) 2595 return false; 2596 2597 TiledBacking* tiledBacking = this->tiledBacking(); 2598 if (!tiledBacking) 2599 return false; 2600 2601 return tiledBacking->hasMargins(); 2602} 2603 2604void FrameView::updateExtendBackgroundIfNecessary() 2605{ 2606 ExtendedBackgroundMode mode = calculateExtendedBackgroundMode(); 2607 if (mode == ExtendedBackgroundModeNone) 2608 return; 2609 2610 updateTilesForExtendedBackgroundMode(mode); 2611} 2612 2613FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const 2614{ 2615 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean 2616 // that the background rect needs to be extended for painting. Simple backgrounds can be extended 2617 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds, 2618 // such as images, require extending the background rect to continue painting into the extended 2619 // region. This function finds out if it is necessary to extend the background rect for painting. 2620 2621#if PLATFORM(IOS) 2622 // <rdar://problem/16201373> 2623 return ExtendedBackgroundModeNone; 2624#endif 2625 2626 if (!frame().settings().backgroundShouldExtendBeyondPage()) 2627 return ExtendedBackgroundModeNone; 2628 2629 if (!frame().isMainFrame()) 2630 return ExtendedBackgroundModeNone; 2631 2632 Document* document = frame().document(); 2633 if (!document) 2634 return ExtendedBackgroundModeNone; 2635 2636 auto documentElement = document->documentElement(); 2637 auto documentElementRenderer = documentElement ? documentElement->renderer() : nullptr; 2638 if (!documentElementRenderer) 2639 return ExtendedBackgroundModeNone; 2640 2641 auto& renderer = documentElementRenderer->rendererForRootBackground(); 2642 if (!renderer.style().hasBackgroundImage()) 2643 return ExtendedBackgroundModeNone; 2644 2645 ExtendedBackgroundMode mode = ExtendedBackgroundModeNone; 2646 2647 if (renderer.style().backgroundRepeatX() == RepeatFill) 2648 mode |= ExtendedBackgroundModeHorizontal; 2649 if (renderer.style().backgroundRepeatY() == RepeatFill) 2650 mode |= ExtendedBackgroundModeVertical; 2651 2652 return mode; 2653} 2654 2655void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode) 2656{ 2657 if (!frame().settings().backgroundShouldExtendBeyondPage()) 2658 return; 2659 2660 RenderView* renderView = this->renderView(); 2661 if (!renderView) 2662 return; 2663 2664 RenderLayerBacking* backing = renderView->layer()->backing(); 2665 if (!backing) 2666 return; 2667 2668 TiledBacking* tiledBacking = backing->graphicsLayer()->tiledBacking(); 2669 if (!tiledBacking) 2670 return; 2671 2672 ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone; 2673 if (tiledBacking->hasVerticalMargins()) 2674 existingMode |= ExtendedBackgroundModeVertical; 2675 if (tiledBacking->hasHorizontalMargins()) 2676 existingMode |= ExtendedBackgroundModeHorizontal; 2677 2678 if (existingMode == mode) 2679 return; 2680 2681 renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor()); 2682 backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical); 2683} 2684 2685IntRect FrameView::extendedBackgroundRectForPainting() const 2686{ 2687 TiledBacking* tiledBacking = this->tiledBacking(); 2688 if (!tiledBacking) 2689 return IntRect(); 2690 2691 RenderView* renderView = this->renderView(); 2692 if (!renderView) 2693 return IntRect(); 2694 2695 LayoutRect extendedRect = renderView->unextendedBackgroundRect(renderView); 2696 if (!tiledBacking->hasMargins()) 2697 return pixelSnappedIntRect(extendedRect); 2698 2699 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight())); 2700 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight())); 2701 return pixelSnappedIntRect(extendedRect); 2702} 2703 2704bool FrameView::shouldUpdateWhileOffscreen() const 2705{ 2706 return m_shouldUpdateWhileOffscreen; 2707} 2708 2709void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen) 2710{ 2711 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen; 2712} 2713 2714bool FrameView::shouldUpdate() const 2715{ 2716 if (isOffscreen() && !shouldUpdateWhileOffscreen()) 2717 return false; 2718 return true; 2719} 2720 2721void FrameView::scrollToAnchor() 2722{ 2723 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor; 2724 if (!anchorNode) 2725 return; 2726 2727 if (!anchorNode->renderer()) 2728 return; 2729 2730 LayoutRect rect; 2731 if (anchorNode != frame().document()) 2732 rect = anchorNode->boundingBox(); 2733 2734 // Scroll nested layers and frames to reveal the anchor. 2735 // Align to the top and to the closest side (this matches other browsers). 2736 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); 2737 2738 if (AXObjectCache* cache = frame().document()->existingAXObjectCache()) 2739 cache->handleScrolledToAnchor(anchorNode.get()); 2740 2741 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor. 2742 m_maintainScrollPositionAnchor = anchorNode; 2743} 2744 2745void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject) 2746{ 2747 // No need to update if it's already crashed or known to be missing. 2748 if (embeddedObject.isPluginUnavailable()) 2749 return; 2750 2751 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement(); 2752 2753 if (embeddedObject.isSnapshottedPlugIn()) { 2754 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) { 2755 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element); 2756 pluginElement.checkSnapshotStatus(); 2757 } 2758 return; 2759 } 2760 2761 auto weakRenderer = embeddedObject.createWeakPtr(); 2762 2763 // FIXME: This could turn into a real virtual dispatch if we defined 2764 // updateWidget(PluginCreationOption) on HTMLElement. 2765 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element) || isHTMLAppletElement(element)) { 2766 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element); 2767 if (pluginElement.needsCheckForSizeChange()) { 2768 pluginElement.checkSnapshotStatus(); 2769 return; 2770 } 2771 if (pluginElement.needsWidgetUpdate()) 2772 pluginElement.updateWidget(CreateAnyWidgetType); 2773 } else 2774 ASSERT_NOT_REACHED(); 2775 2776 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript. 2777 if (!weakRenderer) 2778 return; 2779 2780 embeddedObject.updateWidgetPosition(); 2781} 2782 2783bool FrameView::updateEmbeddedObjects() 2784{ 2785 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty()) 2786 return true; 2787 2788 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; 2789 2790 // Insert a marker for where we should stop. 2791 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr)); 2792 m_embeddedObjectsToUpdate->add(nullptr); 2793 2794 while (!m_embeddedObjectsToUpdate->isEmpty()) { 2795 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst(); 2796 if (!embeddedObject) 2797 break; 2798 updateEmbeddedObject(*embeddedObject); 2799 } 2800 2801 return m_embeddedObjectsToUpdate->isEmpty(); 2802} 2803 2804void FrameView::updateEmbeddedObjectsTimerFired(Timer<FrameView>*) 2805{ 2806 RefPtr<FrameView> protect(this); 2807 m_updateEmbeddedObjectsTimer.stop(); 2808 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) { 2809 if (updateEmbeddedObjects()) 2810 break; 2811 } 2812} 2813 2814void FrameView::flushAnyPendingPostLayoutTasks() 2815{ 2816 if (m_postLayoutTasksTimer.isActive()) 2817 performPostLayoutTasks(); 2818 if (m_updateEmbeddedObjectsTimer.isActive()) 2819 updateEmbeddedObjectsTimerFired(nullptr); 2820} 2821 2822void FrameView::performPostLayoutTasks() 2823{ 2824 // FIXME: We should not run any JavaScript code in this function. 2825 2826 m_postLayoutTasksTimer.stop(); 2827 2828 frame().selection().didLayout(); 2829 2830 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement()) 2831 fireLayoutRelatedMilestonesIfNeeded(); 2832 2833#if PLATFORM(IOS) 2834 // Only send layout-related delegate callbacks synchronously for the main frame to 2835 // avoid re-entering layout for the main frame while delivering a layout-related delegate 2836 // callback for a subframe. 2837 if (frame().isMainFrame()) 2838 frame().page()->chrome().client().didLayout(); 2839#endif 2840 2841#if ENABLE(FONT_LOAD_EVENTS) 2842 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled()) 2843 frame().document()->fontloader()->didLayout(); 2844#endif 2845 2846 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this 2847 // with didLayout(LayoutMilestones). 2848 frame().loader().client().dispatchDidLayout(); 2849 2850 updateWidgetPositions(); 2851 2852 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects() 2853 // is called through the post layout timer. 2854 Ref<FrameView> protect(*this); 2855 2856 m_updateEmbeddedObjectsTimer.startOneShot(0); 2857 2858 if (auto* page = frame().page()) { 2859 if (auto* scrollingCoordinator = page->scrollingCoordinator()) 2860 scrollingCoordinator->frameViewLayoutUpdated(this); 2861 } 2862 2863 if (RenderView* renderView = this->renderView()) { 2864 if (renderView->usesCompositing()) 2865 renderView->compositor().frameViewDidLayout(); 2866 } 2867 2868 scrollToAnchor(); 2869 2870 sendResizeEventIfNeeded(); 2871} 2872 2873IntSize FrameView::sizeForResizeEvent() const 2874{ 2875#if PLATFORM(IOS) 2876 if (m_useCustomSizeForResizeEvent) 2877 return m_customSizeForResizeEvent; 2878#endif 2879 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) 2880 return fixedLayoutSize(); 2881 return visibleContentRectIncludingScrollbars().size(); 2882} 2883 2884void FrameView::sendResizeEventIfNeeded() 2885{ 2886 if (isInLayout() || needsLayout()) 2887 return; 2888 2889 RenderView* renderView = this->renderView(); 2890 if (!renderView || renderView->printing()) 2891 return; 2892 2893 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient()) 2894 return; 2895 2896 IntSize currentSize = sizeForResizeEvent(); 2897 float currentZoomFactor = renderView->style().zoom(); 2898 2899 if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor) 2900 return; 2901 2902 m_lastViewportSize = currentSize; 2903 m_lastZoomFactor = currentZoomFactor; 2904 2905 if (m_firstLayout) 2906 return; 2907 2908#if PLATFORM(IOS) 2909 // Don't send the resize event if the document is loading. Some pages automatically reload 2910 // when the window is resized; Safari on iOS often resizes the window while setting up its 2911 // viewport. This obviously can cause problems. 2912 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) { 2913 if (documentLoader->isLoadingInAPISense()) 2914 return; 2915 } 2916#endif 2917 2918 bool isMainFrame = frame().isMainFrame(); 2919 bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize; 2920 2921 RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false); 2922 if (canSendResizeEventSynchronously) 2923 frame().document()->dispatchWindowEvent(resizeEvent.release()); 2924 else { 2925 // FIXME: Queueing this event for an unpredictable time in the future seems 2926 // intrinsically racy. By the time this resize event fires, the frame might 2927 // be resized again, so we could end up with two resize events for the same size. 2928 frame().document()->enqueueWindowEvent(resizeEvent.release()); 2929 } 2930 2931#if ENABLE(INSPECTOR) 2932 if (InspectorInstrumentation::hasFrontends() && isMainFrame) { 2933 if (Page* page = frame().page()) { 2934 if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient()) 2935 inspectorClient->didResizeMainFrame(&frame()); 2936 } 2937 } 2938#endif 2939} 2940 2941void FrameView::willStartLiveResize() 2942{ 2943 ScrollView::willStartLiveResize(); 2944 adjustTiledBackingCoverage(); 2945} 2946 2947void FrameView::willEndLiveResize() 2948{ 2949 ScrollView::willEndLiveResize(); 2950 adjustTiledBackingCoverage(); 2951} 2952 2953void FrameView::postLayoutTimerFired(Timer<FrameView>&) 2954{ 2955 performPostLayoutTasks(); 2956} 2957 2958void FrameView::autoSizeIfEnabled() 2959{ 2960 if (!m_shouldAutoSize) 2961 return; 2962 2963 if (m_inAutoSize) 2964 return; 2965 2966 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true); 2967 2968 Document* document = frame().document(); 2969 if (!document) 2970 return; 2971 2972 RenderView* documentView = document->renderView(); 2973 Element* documentElement = document->documentElement(); 2974 if (!documentView || !documentElement) 2975 return; 2976 2977 // Start from the minimum size and allow it to grow. 2978 resize(m_minAutoSize.width(), m_minAutoSize.height()); 2979 2980 IntSize size = frameRect().size(); 2981 2982 // Do the resizing twice. The first time is basically a rough calculation using the preferred width 2983 // which may result in a height change during the second iteration. 2984 for (int i = 0; i < 2; i++) { 2985 // Update various sizes including contentsSize, scrollHeight, etc. 2986 document->updateLayoutIgnorePendingStylesheets(); 2987 int width = documentView->minPreferredLogicalWidth(); 2988 int height = documentView->documentRect().height(); 2989 IntSize newSize(width, height); 2990 2991 // Check to see if a scrollbar is needed for a given dimension and 2992 // if so, increase the other dimension to account for the scrollbar. 2993 // Since the dimensions are only for the view rectangle, once a 2994 // dimension exceeds the maximum, there is no need to increase it further. 2995 if (newSize.width() > m_maxAutoSize.width()) { 2996 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar(); 2997 if (!localHorizontalScrollbar) 2998 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar); 2999 if (!localHorizontalScrollbar->isOverlayScrollbar()) 3000 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height()); 3001 3002 // Don't bother checking for a vertical scrollbar because the width is at 3003 // already greater the maximum. 3004 } else if (newSize.height() > m_maxAutoSize.height()) { 3005 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar(); 3006 if (!localVerticalScrollbar) 3007 localVerticalScrollbar = createScrollbar(VerticalScrollbar); 3008 if (!localVerticalScrollbar->isOverlayScrollbar()) 3009 newSize.setWidth(newSize.width() + localVerticalScrollbar->width()); 3010 3011 // Don't bother checking for a horizontal scrollbar because the height is 3012 // already greater the maximum. 3013 } 3014 3015 // Ensure the size is at least the min bounds. 3016 newSize = newSize.expandedTo(m_minAutoSize); 3017 3018 // Bound the dimensions by the max bounds and determine what scrollbars to show. 3019 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff; 3020 if (newSize.width() > m_maxAutoSize.width()) { 3021 newSize.setWidth(m_maxAutoSize.width()); 3022 horizonalScrollbarMode = ScrollbarAlwaysOn; 3023 } 3024 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff; 3025 if (newSize.height() > m_maxAutoSize.height()) { 3026 newSize.setHeight(m_maxAutoSize.height()); 3027 verticalScrollbarMode = ScrollbarAlwaysOn; 3028 } 3029 3030 if (newSize == size) 3031 continue; 3032 3033 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states) 3034 // unless autoresize has just been turned on or the maximum size is smaller than the current size. 3035 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width() 3036 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width())) 3037 break; 3038 3039 resize(newSize.width(), newSize.height()); 3040 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example, 3041 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed). 3042 setVerticalScrollbarLock(false); 3043 setHorizontalScrollbarLock(false); 3044 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true); 3045 } 3046 3047 m_autoSizeContentSize = contentsSize(); 3048 3049 if (m_autoSizeFixedMinimumHeight) { 3050 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height())); 3051 document->updateLayoutIgnorePendingStylesheets(); 3052 } 3053 3054 m_didRunAutosize = true; 3055} 3056 3057void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight) 3058{ 3059 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight) 3060 return; 3061 3062 m_autoSizeFixedMinimumHeight = fixedMinimumHeight; 3063 3064 setNeedsLayout(); 3065} 3066 3067void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) 3068{ 3069 if (!m_viewportRenderer) 3070 return; 3071 3072 if (m_overflowStatusDirty) { 3073 m_horizontalOverflow = horizontalOverflow; 3074 m_verticalOverflow = verticalOverflow; 3075 m_overflowStatusDirty = false; 3076 return; 3077 } 3078 3079 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow); 3080 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow); 3081 3082 if (horizontalOverflowChanged || verticalOverflowChanged) { 3083 m_horizontalOverflow = horizontalOverflow; 3084 m_verticalOverflow = verticalOverflow; 3085 3086 RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, 3087 verticalOverflowChanged, verticalOverflow); 3088 overflowEvent->setTarget(m_viewportRenderer->element()); 3089 3090 frame().document()->enqueueOverflowEvent(overflowEvent.release()); 3091 } 3092 3093} 3094 3095const Pagination& FrameView::pagination() const 3096{ 3097 if (m_pagination != Pagination()) 3098 return m_pagination; 3099 3100 if (frame().isMainFrame()) 3101 return frame().page()->pagination(); 3102 3103 return m_pagination; 3104} 3105 3106void FrameView::setPagination(const Pagination& pagination) 3107{ 3108 if (m_pagination == pagination) 3109 return; 3110 3111 m_pagination = pagination; 3112 3113 frame().document()->styleResolverChanged(DeferRecalcStyle); 3114} 3115 3116IntRect FrameView::windowClipRect(bool clipToContents) const 3117{ 3118 ASSERT(frame().view() == this); 3119 3120 if (paintsEntireContents()) 3121 return IntRect(IntPoint(), totalContentsSize()); 3122 3123 // Set our clip rect to be our contents. 3124 IntRect clipRect; 3125 if (clipToContents) 3126 clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect)); 3127 else 3128 clipRect = contentsToWindow(visibleContentRectIncludingScrollbars(LegacyIOSDocumentVisibleRect)); 3129 if (!frame().ownerElement()) 3130 return clipRect; 3131 3132 // Take our owner element and get its clip rect. 3133 HTMLFrameOwnerElement* ownerElement = frame().ownerElement(); 3134 if (FrameView* parentView = ownerElement->document().view()) 3135 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true)); 3136 return clipRect; 3137} 3138 3139IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const 3140{ 3141 // The renderer can sometimes be null when style="display:none" interacts 3142 // with external content and plugins. 3143 if (!ownerElement->renderer()) 3144 return windowClipRect(); 3145 3146 // If we have no layer, just return our window clip rect. 3147 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer(); 3148 if (!enclosingLayer) 3149 return windowClipRect(); 3150 3151 // Apply the clip from the layer. 3152 IntRect clipRect; 3153 if (clipToLayerContents) 3154 clipRect = pixelSnappedIntRect(enclosingLayer->childrenClipRect()); 3155 else 3156 clipRect = pixelSnappedIntRect(enclosingLayer->selfClipRect()); 3157 clipRect = contentsToWindow(clipRect); 3158 return intersection(clipRect, windowClipRect()); 3159} 3160 3161bool FrameView::isActive() const 3162{ 3163 Page* page = frame().page(); 3164 return page && page->focusController().isActive(); 3165} 3166 3167bool FrameView::updatesScrollLayerPositionOnMainThread() const 3168{ 3169 if (Page* page = frame().page()) { 3170 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) 3171 return scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(); 3172 } 3173 3174 return true; 3175} 3176 3177bool FrameView::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const 3178{ 3179 Page* page = frame().page(); 3180 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting(); 3181} 3182 3183void FrameView::scrollTo(const IntSize& newOffset) 3184{ 3185 LayoutSize offset = scrollOffset(); 3186 IntPoint oldPosition = scrollPosition(); 3187 ScrollView::scrollTo(newOffset); 3188 if (offset != scrollOffset()) 3189 scrollPositionChanged(oldPosition, scrollPosition()); 3190 frame().loader().client().didChangeScrollOffset(); 3191} 3192 3193void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) 3194{ 3195 // Add in our offset within the FrameView. 3196 IntRect dirtyRect = rect; 3197 dirtyRect.moveBy(scrollbar->location()); 3198 invalidateRect(dirtyRect); 3199} 3200 3201IntRect FrameView::windowResizerRect() const 3202{ 3203 if (Page* page = frame().page()) 3204 return page->chrome().windowResizerRect(); 3205 return IntRect(); 3206} 3207 3208float FrameView::visibleContentScaleFactor() const 3209{ 3210 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling()) 3211 return 1; 3212 3213 return frame().page()->pageScaleFactor(); 3214} 3215 3216void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb) 3217{ 3218 if (!frame().isMainFrame()) 3219 return; 3220 3221 frame().page()->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb); 3222} 3223 3224ScrollableArea* FrameView::enclosingScrollableArea() const 3225{ 3226 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer. 3227 return 0; 3228} 3229 3230IntRect FrameView::scrollableAreaBoundingBox() const 3231{ 3232 RenderWidget* ownerRenderer = frame().ownerRenderer(); 3233 if (!ownerRenderer) 3234 return frameRect(); 3235 3236 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox(); 3237} 3238 3239bool FrameView::isScrollable() 3240{ 3241 // Check for: 3242 // 1) If there an actual overflow. 3243 // 2) display:none or visibility:hidden set to self or inherited. 3244 // 3) overflow{-x,-y}: hidden; 3245 // 4) scrolling: no; 3246 3247 // Covers #1 3248 IntSize totalContentsSize = this->totalContentsSize(); 3249 IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size(); 3250 if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width())) 3251 return false; 3252 3253 // Covers #2. 3254 HTMLFrameOwnerElement* owner = frame().ownerElement(); 3255 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting())) 3256 return false; 3257 3258 // Cover #3 and #4. 3259 ScrollbarMode horizontalMode; 3260 ScrollbarMode verticalMode; 3261 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly); 3262 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) 3263 return false; 3264 3265 return true; 3266} 3267 3268void FrameView::updateScrollableAreaSet() 3269{ 3270 // That ensures that only inner frames are cached. 3271 FrameView* parentFrameView = this->parentFrameView(); 3272 if (!parentFrameView) 3273 return; 3274 3275 if (!isScrollable()) { 3276 parentFrameView->removeScrollableArea(this); 3277 return; 3278 } 3279 3280 parentFrameView->addScrollableArea(this); 3281} 3282 3283bool FrameView::shouldSuspendScrollAnimations() const 3284{ 3285 return frame().loader().state() != FrameStateComplete; 3286} 3287 3288void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate) 3289{ 3290 if (!frame().isMainFrame()) 3291 return; 3292 3293 frame().page()->chrome().client().recommendedScrollbarStyleDidChange(newStyle); 3294 3295 if (forceUpdate) 3296 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate); 3297} 3298 3299void FrameView::notifyPageThatContentAreaWillPaint() const 3300{ 3301 Page* page = frame().page(); 3302 if (!page) 3303 return; 3304 3305 contentAreaWillPaint(); 3306 3307 if (!m_scrollableAreas) 3308 return; 3309 3310 for (auto& scrollableArea : *m_scrollableAreas) 3311 scrollableArea->contentAreaWillPaint(); 3312} 3313 3314bool FrameView::scrollAnimatorEnabled() const 3315{ 3316#if ENABLE(SMOOTH_SCROLLING) 3317 if (Page* page = frame().page()) 3318 return page->settings().scrollAnimatorEnabled(); 3319#endif 3320 3321 return false; 3322} 3323 3324#if ENABLE(DASHBOARD_SUPPORT) 3325void FrameView::updateAnnotatedRegions() 3326{ 3327 Document* document = frame().document(); 3328 if (!document->hasAnnotatedRegions()) 3329 return; 3330 Vector<AnnotatedRegionValue> newRegions; 3331 document->renderBox()->collectAnnotatedRegions(newRegions); 3332 if (newRegions == document->annotatedRegions()) 3333 return; 3334 document->setAnnotatedRegions(newRegions); 3335 Page* page = frame().page(); 3336 if (!page) 3337 return; 3338 page->chrome().client().annotatedRegionsChanged(); 3339} 3340#endif 3341 3342void FrameView::updateScrollCorner() 3343{ 3344 RenderElement* renderer = 0; 3345 RefPtr<RenderStyle> cornerStyle; 3346 IntRect cornerRect = scrollCornerRect(); 3347 3348 if (!cornerRect.isEmpty()) { 3349 // Try the <body> element first as a scroll corner source. 3350 Document* doc = frame().document(); 3351 Element* body = doc ? doc->body() : 0; 3352 if (body && body->renderer()) { 3353 renderer = body->renderer(); 3354 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style()); 3355 } 3356 3357 if (!cornerStyle) { 3358 // If the <body> didn't have a custom style, then the root element might. 3359 Element* docElement = doc ? doc->documentElement() : 0; 3360 if (docElement && docElement->renderer()) { 3361 renderer = docElement->renderer(); 3362 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style()); 3363 } 3364 } 3365 3366 if (!cornerStyle) { 3367 // If we have an owning iframe/frame element, then it can set the custom scrollbar also. 3368 if (RenderWidget* renderer = frame().ownerRenderer()) 3369 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style()); 3370 } 3371 } 3372 3373 if (!cornerStyle) 3374 m_scrollCorner = nullptr; 3375 else { 3376 if (!m_scrollCorner) { 3377 m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer->document(), cornerStyle.releaseNonNull()); 3378 m_scrollCorner->initializeStyle(); 3379 } else 3380 m_scrollCorner->setStyle(cornerStyle.releaseNonNull()); 3381 invalidateScrollCorner(cornerRect); 3382 } 3383 3384 ScrollView::updateScrollCorner(); 3385} 3386 3387void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) 3388{ 3389 if (context->updatingControlTints()) { 3390 updateScrollCorner(); 3391 return; 3392 } 3393 3394 if (m_scrollCorner) { 3395 if (frame().isMainFrame()) 3396 context->fillRect(cornerRect, baseBackgroundColor(), ColorSpaceDeviceRGB); 3397 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect); 3398 return; 3399 } 3400 3401 ScrollView::paintScrollCorner(context, cornerRect); 3402} 3403 3404void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect) 3405{ 3406 if (bar->isCustomScrollbar() && frame().isMainFrame()) { 3407 IntRect toFill = bar->frameRect(); 3408 toFill.intersect(rect); 3409 context->fillRect(toFill, baseBackgroundColor(), ColorSpaceDeviceRGB); 3410 } 3411 3412 ScrollView::paintScrollbar(context, bar, rect); 3413} 3414 3415Color FrameView::documentBackgroundColor() const 3416{ 3417 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of 3418 // the document and the body against the base background color of the frame view. 3419 // Background images are unfortunately impractical to include. 3420 3421 // Return invalid Color objects whenever there is insufficient information. 3422 if (!frame().document()) 3423 return Color(); 3424 3425 Element* htmlElement = frame().document()->documentElement(); 3426 Element* bodyElement = frame().document()->body(); 3427 3428 // Start with invalid colors. 3429 Color htmlBackgroundColor; 3430 Color bodyBackgroundColor; 3431 if (htmlElement && htmlElement->renderer()) 3432 htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor); 3433 if (bodyElement && bodyElement->renderer()) 3434 bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor); 3435 3436 if (!bodyBackgroundColor.isValid()) { 3437 if (!htmlBackgroundColor.isValid()) 3438 return Color(); 3439 return baseBackgroundColor().blend(htmlBackgroundColor); 3440 } 3441 3442 if (!htmlBackgroundColor.isValid()) 3443 return baseBackgroundColor().blend(bodyBackgroundColor); 3444 3445 // We take the aggregate of the base background color 3446 // the <html> background color, and the <body> 3447 // background color to find the document color. The 3448 // addition of the base background color is not 3449 // technically part of the document background, but it 3450 // otherwise poses problems when the aggregate is not 3451 // fully opaque. 3452 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor); 3453} 3454 3455bool FrameView::hasCustomScrollbars() const 3456{ 3457 for (auto& widget : children()) { 3458 if (widget->isFrameView()) { 3459 if (toFrameView(*widget).hasCustomScrollbars()) 3460 return true; 3461 } else if (widget->isScrollbar()) { 3462 if (toScrollbar(*widget).isCustomScrollbar()) 3463 return true; 3464 } 3465 } 3466 3467 return false; 3468} 3469 3470FrameView* FrameView::parentFrameView() const 3471{ 3472 if (!parent()) 3473 return 0; 3474 3475 if (Frame* parentFrame = frame().tree().parent()) 3476 return parentFrame->view(); 3477 3478 return 0; 3479} 3480 3481bool FrameView::isInChildFrameWithFrameFlattening() const 3482{ 3483 if (!parent() || !frame().ownerElement()) 3484 return false; 3485 3486 // Frame flattening applies when the owner element is either in a frameset or 3487 // an iframe with flattening parameters. 3488 if (frame().ownerElement()->hasTagName(iframeTag)) { 3489 RenderIFrame* iframeRenderer = toRenderIFrame(frame().ownerElement()->renderWidget()); 3490 if (iframeRenderer->flattenFrame()) 3491 return true; 3492 } 3493 3494 if (!frameFlatteningEnabled()) 3495 return false; 3496 3497 if (frame().ownerElement()->hasTagName(frameTag)) 3498 return true; 3499 3500 return false; 3501} 3502 3503void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree) 3504{ 3505 // When we start a layout at the child level as opposed to the topmost frame view and this child 3506 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout 3507 // will hit this view eventually. 3508 FrameView* parentView = parentFrameView(); 3509 if (!parentView) 3510 return; 3511 3512 // In the middle of parent layout, no need to restart from topmost. 3513 if (parentView->m_nestedLayoutCount) 3514 return; 3515 3516 // Parent tree is clean. Starting layout from it would have no effect. 3517 if (!parentView->needsLayout()) 3518 return; 3519 3520 while (parentView->parentFrameView()) 3521 parentView = parentView->parentFrameView(); 3522 3523 parentView->layout(allowSubtree); 3524 3525 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView(); 3526 ASSERT_UNUSED(root, !root->needsLayout()); 3527} 3528 3529void FrameView::updateControlTints() 3530{ 3531 // This is called when control tints are changed from aqua/graphite to clear and vice versa. 3532 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate. 3533 // This is only done if the theme supports control tinting. It's up to the theme and platform 3534 // to define when controls get the tint and to call this function when that changes. 3535 3536 // Optimize the common case where we bring a window to the front while it's still empty. 3537 if (frame().document()->url().isEmpty()) 3538 return; 3539 3540 RenderView* renderView = this->renderView(); 3541 if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars()) 3542 paintControlTints(); 3543} 3544 3545void FrameView::paintControlTints() 3546{ 3547 if (needsLayout()) 3548 layout(); 3549 PlatformGraphicsContext* const noContext = 0; 3550 GraphicsContext context(noContext); 3551 context.setUpdatingControlTints(true); 3552 if (platformWidget()) { 3553 // FIXME: consult paintsEntireContents(). 3554 paintContents(&context, visibleContentRect(LegacyIOSDocumentVisibleRect)); 3555 } else 3556 paint(&context, frameRect()); 3557} 3558 3559bool FrameView::wasScrolledByUser() const 3560{ 3561 return m_wasScrolledByUser; 3562} 3563 3564void FrameView::setWasScrolledByUser(bool wasScrolledByUser) 3565{ 3566 if (m_inProgrammaticScroll) 3567 return; 3568 m_maintainScrollPositionAnchor = 0; 3569 if (m_wasScrolledByUser == wasScrolledByUser) 3570 return; 3571 m_wasScrolledByUser = wasScrolledByUser; 3572 if (frame().isMainFrame()) 3573 updateLayerFlushThrottling(); 3574 adjustTiledBackingCoverage(); 3575} 3576 3577void FrameView::willPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState) 3578{ 3579 Document* document = frame().document(); 3580 3581 if (!context->paintingDisabled()) 3582 InspectorInstrumentation::willPaint(renderView()); 3583 3584 paintingState.isTopLevelPainter = !sCurrentPaintTimeStamp; 3585 3586 if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure()) { 3587 LOG(MemoryPressure, "Under memory pressure: %s", WTF_PRETTY_FUNCTION); 3588 3589 // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since 3590 // we might need some live bitmaps on painting. 3591 memoryCache()->prune(); 3592 } 3593 3594 if (paintingState.isTopLevelPainter) 3595 sCurrentPaintTimeStamp = monotonicallyIncreasingTime(); 3596 3597 paintingState.paintBehavior = m_paintBehavior; 3598 3599 if (FrameView* parentView = parentFrameView()) { 3600 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers) 3601 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers; 3602 } 3603 3604 if (m_paintBehavior == PaintBehaviorNormal) 3605 document->markers().invalidateRenderedRectsForMarkersInRect(dirtyRect); 3606 3607 if (document->printing()) 3608 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers; 3609 3610 paintingState.isFlatteningPaintOfRootFrame = (m_paintBehavior & PaintBehaviorFlattenCompositingLayers) && !frame().ownerElement(); 3611 if (paintingState.isFlatteningPaintOfRootFrame) 3612 notifyWidgetsInAllFrames(WillPaintFlattened); 3613 3614 ASSERT(!m_isPainting); 3615 m_isPainting = true; 3616} 3617 3618void FrameView::didPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState) 3619{ 3620 m_isPainting = false; 3621 3622 if (paintingState.isFlatteningPaintOfRootFrame) 3623 notifyWidgetsInAllFrames(DidPaintFlattened); 3624 3625 m_paintBehavior = paintingState.paintBehavior; 3626 m_lastPaintTime = monotonicallyIncreasingTime(); 3627 3628 // Painting can lead to decoding of large amounts of bitmaps 3629 // If we are low on memory, wipe them out after the paint. 3630 if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure()) 3631 memoryCache()->pruneLiveResources(true); 3632 3633 // Regions may have changed as a result of the visibility/z-index of element changing. 3634#if ENABLE(DASHBOARD_SUPPORT) 3635 if (frame().document()->annotatedRegionsDirty()) 3636 updateAnnotatedRegions(); 3637#endif 3638 3639 if (paintingState.isTopLevelPainter) 3640 sCurrentPaintTimeStamp = 0; 3641 3642 if (!context->paintingDisabled()) { 3643 InspectorInstrumentation::didPaint(renderView(), context, dirtyRect); 3644 // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623 3645 firePaintRelatedMilestonesIfNeeded(); 3646 } 3647} 3648 3649void FrameView::paintContents(GraphicsContext* context, const IntRect& dirtyRect) 3650{ 3651#ifndef NDEBUG 3652 bool fillWithRed; 3653 if (frame().document()->printing()) 3654 fillWithRed = false; // Printing, don't fill with red (can't remember why). 3655 else if (frame().ownerElement()) 3656 fillWithRed = false; // Subframe, don't fill with red. 3657 else if (isTransparent()) 3658 fillWithRed = false; // Transparent, don't fill with red. 3659 else if (m_paintBehavior & PaintBehaviorSelectionOnly) 3660 fillWithRed = false; // Selections are transparent, don't fill with red. 3661 else if (m_nodeToDraw) 3662 fillWithRed = false; // Element images are transparent, don't fill with red. 3663 else 3664 fillWithRed = true; 3665 3666 if (fillWithRed) 3667 context->fillRect(dirtyRect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB); 3668#endif 3669 3670 RenderView* renderView = this->renderView(); 3671 if (!renderView) { 3672 LOG_ERROR("called FrameView::paint with nil renderer"); 3673 return; 3674 } 3675 3676 ASSERT(!needsLayout()); 3677 if (needsLayout()) 3678 return; 3679 3680 PaintingState paintingState; 3681 willPaintContents(context, dirtyRect, paintingState); 3682 3683 FontCachePurgePreventer fontCachePurgePreventer; 3684 3685 // m_nodeToDraw is used to draw only one element (and its descendants) 3686 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; 3687 RenderLayer* rootLayer = renderView->layer(); 3688 3689#ifndef NDEBUG 3690 RenderElement::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(&rootLayer->renderer()); 3691#endif 3692 3693 // To work around http://webkit.org/b/135106, ensure that the paint root isn't an inline with culled line boxes. 3694 // FIXME: This can cause additional content to be included in the snapshot, so remove this once that bug is fixed. 3695 while (eltRenderer && eltRenderer->isRenderInline() && !toRenderInline(eltRenderer)->firstLineBox()) 3696 eltRenderer = eltRenderer->parent(); 3697 3698 rootLayer->paint(context, dirtyRect, m_paintBehavior, eltRenderer); 3699 if (rootLayer->containsDirtyOverlayScrollbars()) 3700 rootLayer->paintOverlayScrollbars(context, dirtyRect, m_paintBehavior, eltRenderer); 3701 3702 didPaintContents(context, dirtyRect, paintingState); 3703} 3704 3705void FrameView::setPaintBehavior(PaintBehavior behavior) 3706{ 3707 m_paintBehavior = behavior; 3708} 3709 3710PaintBehavior FrameView::paintBehavior() const 3711{ 3712 return m_paintBehavior; 3713} 3714 3715bool FrameView::isPainting() const 3716{ 3717 return m_isPainting; 3718} 3719 3720// FIXME: change this to use the subtreePaint terminology. 3721void FrameView::setNodeToDraw(Node* node) 3722{ 3723 m_nodeToDraw = node; 3724} 3725 3726void FrameView::paintContentsForSnapshot(GraphicsContext* context, const IntRect& imageRect, SelectionInSnapshot shouldPaintSelection, CoordinateSpaceForSnapshot coordinateSpace) 3727{ 3728 updateLayoutAndStyleIfNeededRecursive(); 3729 3730 // Cache paint behavior and set a new behavior appropriate for snapshots. 3731 PaintBehavior oldBehavior = paintBehavior(); 3732 setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers); 3733 3734 // If the snapshot should exclude selection, then we'll clear the current selection 3735 // in the render tree only. This will allow us to restore the selection from the DOM 3736 // after we paint the snapshot. 3737 if (shouldPaintSelection == ExcludeSelection) { 3738 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 3739 if (RenderView* root = frame->contentRenderer()) 3740 root->clearSelection(); 3741 } 3742 } 3743 3744 if (coordinateSpace == DocumentCoordinates) 3745 paintContents(context, imageRect); 3746 else { 3747 // A snapshot in ViewCoordinates will include a scrollbar, and the snapshot will contain 3748 // whatever content the document is currently scrolled to. 3749 paint(context, imageRect); 3750 } 3751 3752 // Restore selection. 3753 if (shouldPaintSelection == ExcludeSelection) { 3754 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) 3755 frame->selection().updateAppearance(); 3756 } 3757 3758 // Restore cached paint behavior. 3759 setPaintBehavior(oldBehavior); 3760} 3761 3762void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect) 3763{ 3764 if (context->paintingDisabled()) 3765 return; 3766 3767 if (frame().document()->printing()) 3768 return; 3769 3770 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect); 3771} 3772 3773void FrameView::updateLayoutAndStyleIfNeededRecursive() 3774{ 3775 // We have to crawl our entire tree looking for any FrameViews that need 3776 // layout and make sure they are up to date. 3777 // Mac actually tests for intersection with the dirty region and tries not to 3778 // update layout for frames that are outside the dirty region. Not only does this seem 3779 // pointless (since those frames will have set a zero timer to layout anyway), but 3780 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty 3781 // region but then become included later by the second frame adding rects to the dirty region 3782 // when it lays out. 3783 3784 frame().document()->updateStyleIfNeeded(); 3785 3786 if (needsLayout()) 3787 layout(); 3788 3789 // Grab a copy of the children() set, as it may be mutated by the following updateLayoutAndStyleIfNeededRecursive 3790 // calls, as they can potentially re-enter a layout of the parent frame view, which may add/remove scrollbars 3791 // and thus mutates the children() set. 3792 Vector<Ref<FrameView>, 16> childViews; 3793 childViews.reserveInitialCapacity(children().size()); 3794 for (auto& widget : children()) { 3795 if (widget->isFrameView()) 3796 childViews.uncheckedAppend(toFrameView(*widget)); 3797 } 3798 3799 for (unsigned i = 0; i < childViews.size(); ++i) 3800 childViews[i]->updateLayoutAndStyleIfNeededRecursive(); 3801 3802 // When frame flattening is on, child frame can mark parent frame dirty. In such case, child frame 3803 // needs to call layout on parent frame recursively. 3804 // This assert ensures that parent frames are clean, when child frames finished updating layout and style. 3805 ASSERT(!needsLayout()); 3806} 3807 3808bool FrameView::qualifiesAsVisuallyNonEmpty() const 3809{ 3810 // No content yet. 3811 Element* documentElement = frame().document()->documentElement(); 3812 if (!documentElement || !documentElement->renderer()) 3813 return false; 3814 3815 // Ensure that we always get marked visually non-empty eventually. 3816 if (!frame().document()->parsing() && frame().loader().stateMachine().committedFirstRealDocumentLoad()) 3817 return true; 3818 3819 // Require the document to grow a bit. 3820 static const int documentHeightThreshold = 200; 3821 if (documentElement->renderBox()->layoutOverflowRect().pixelSnappedHeight() < documentHeightThreshold) 3822 return false; 3823 3824 // The first few hundred characters rarely contain the interesting content of the page. 3825 if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold) 3826 return true; 3827 // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout 3828 if (m_visuallyNonEmptyPixelCount > visualPixelThreshold) 3829 return true; 3830 return false; 3831} 3832 3833void FrameView::updateIsVisuallyNonEmpty() 3834{ 3835 if (m_isVisuallyNonEmpty) 3836 return; 3837 if (!qualifiesAsVisuallyNonEmpty()) 3838 return; 3839 m_isVisuallyNonEmpty = true; 3840 adjustTiledBackingCoverage(); 3841} 3842 3843void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize) 3844{ 3845 ASSERT(!enable || !minSize.isEmpty()); 3846 ASSERT(minSize.width() <= maxSize.width()); 3847 ASSERT(minSize.height() <= maxSize.height()); 3848 3849 if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize) 3850 return; 3851 3852 m_shouldAutoSize = enable; 3853 m_minAutoSize = minSize; 3854 m_maxAutoSize = maxSize; 3855 m_didRunAutosize = false; 3856 3857 setNeedsLayout(); 3858 scheduleRelayout(); 3859 if (m_shouldAutoSize) 3860 return; 3861 3862 // Since autosize mode forces the scrollbar mode, change them to being auto. 3863 setVerticalScrollbarLock(false); 3864 setHorizontalScrollbarLock(false); 3865 setScrollbarModes(ScrollbarAuto, ScrollbarAuto); 3866} 3867 3868void FrameView::forceLayout(bool allowSubtree) 3869{ 3870 layout(allowSubtree); 3871} 3872 3873void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor, AdjustViewSizeOrNot shouldAdjustViewSize) 3874{ 3875 // Dumping externalRepresentation(frame().renderer()).ascii() is a good trick to see 3876 // the state of things before and after the layout 3877 if (RenderView* renderView = this->renderView()) { 3878 float pageLogicalWidth = renderView->style().isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); 3879 float pageLogicalHeight = renderView->style().isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); 3880 3881 renderView->setLogicalWidth(floor(pageLogicalWidth)); 3882 renderView->setPageLogicalHeight(floor(pageLogicalHeight)); 3883 renderView->setNeedsLayoutAndPrefWidthsRecalc(); 3884 forceLayout(); 3885 3886 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the 3887 // page width when shrunk, we will lay out at maximum shrink and clip extra content. 3888 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping 3889 // implementation should not do this! 3890 bool horizontalWritingMode = renderView->style().isHorizontalWritingMode(); 3891 const LayoutRect& documentRect = renderView->documentRect(); 3892 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height(); 3893 if (docLogicalWidth > pageLogicalWidth) { 3894 int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor); 3895 int expectedPageHeight = std::min<float>(documentRect.height(), pageSize.height() * maximumShrinkFactor); 3896 FloatSize maxPageSize = frame().resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), FloatSize(expectedPageWidth, expectedPageHeight)); 3897 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height(); 3898 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width(); 3899 3900 renderView->setLogicalWidth(floor(pageLogicalWidth)); 3901 renderView->setPageLogicalHeight(floor(pageLogicalHeight)); 3902 renderView->setNeedsLayoutAndPrefWidthsRecalc(); 3903 forceLayout(); 3904 3905 const LayoutRect& updatedDocumentRect = renderView->documentRect(); 3906 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width(); 3907 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x(); 3908 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY(); 3909 LayoutUnit clippedLogicalLeft = 0; 3910 if (!renderView->style().isLeftToRightDirection()) 3911 clippedLogicalLeft = docLogicalRight - pageLogicalWidth; 3912 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight); 3913 3914 if (!horizontalWritingMode) 3915 overflow = overflow.transposedRect(); 3916 renderView->clearLayoutOverflow(); 3917 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. 3918 } 3919 } 3920 3921 if (shouldAdjustViewSize) 3922 adjustViewSize(); 3923} 3924 3925void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/) 3926{ 3927 RenderView* renderView = this->renderView(); 3928 if (!renderView) { 3929 *newBottom = oldBottom; 3930 return; 3931 3932 } 3933 // Use a context with painting disabled. 3934 GraphicsContext context((PlatformGraphicsContext*)0); 3935 renderView->setTruncatedAt(static_cast<int>(floorf(oldBottom))); 3936 IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), renderView->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop))); 3937 renderView->setPrintRect(dirtyRect); 3938 renderView->layer()->paint(&context, dirtyRect); 3939 *newBottom = renderView->bestTruncatedAt(); 3940 if (!*newBottom) 3941 *newBottom = oldBottom; 3942 renderView->setPrintRect(IntRect()); 3943} 3944 3945IntRect FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntRect& rendererRect) const 3946{ 3947 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox())); 3948 3949 // Convert from page ("absolute") to FrameView coordinates. 3950 if (!delegatesScrolling()) 3951 rect.moveBy(-scrollPosition() + IntPoint(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset))); 3952 3953 return rect; 3954} 3955 3956IntRect FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntRect& viewRect) const 3957{ 3958 IntRect rect = viewRect; 3959 3960 // Convert from FrameView coords into page ("absolute") coordinates. 3961 if (!delegatesScrolling()) 3962 rect.moveBy(documentScrollPositionRelativeToViewOrigin()); 3963 3964 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just 3965 // move the rect for now. 3966 rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms))); 3967 return rect; 3968} 3969 3970IntPoint FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntPoint& rendererPoint) const 3971{ 3972 IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms)); 3973 3974 // Convert from page ("absolute") to FrameView coordinates. 3975 if (!delegatesScrolling()) 3976 point.moveBy(-scrollPosition() + IntPoint(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset))); 3977 return point; 3978} 3979 3980IntPoint FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntPoint& viewPoint) const 3981{ 3982 IntPoint point = viewPoint; 3983 3984 // Convert from FrameView coords into page ("absolute") coordinates. 3985 if (!delegatesScrolling()) 3986 point = point + documentScrollPositionRelativeToViewOrigin(); 3987 3988 return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms)); 3989} 3990 3991IntRect FrameView::convertToContainingView(const IntRect& localRect) const 3992{ 3993 if (const ScrollView* parentScrollView = parent()) { 3994 if (parentScrollView->isFrameView()) { 3995 const FrameView* parentView = toFrameView(parentScrollView); 3996 // Get our renderer in the parent view 3997 RenderWidget* renderer = frame().ownerRenderer(); 3998 if (!renderer) 3999 return localRect; 4000 4001 IntRect rect(localRect); 4002 // Add borders and padding?? 4003 rect.move(renderer->borderLeft() + renderer->paddingLeft(), 4004 renderer->borderTop() + renderer->paddingTop()); 4005 return parentView->convertFromRendererToContainingView(renderer, rect); 4006 } 4007 4008 return Widget::convertToContainingView(localRect); 4009 } 4010 4011 return localRect; 4012} 4013 4014IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const 4015{ 4016 if (const ScrollView* parentScrollView = parent()) { 4017 if (parentScrollView->isFrameView()) { 4018 const FrameView* parentView = toFrameView(parentScrollView); 4019 4020 // Get our renderer in the parent view 4021 RenderWidget* renderer = frame().ownerRenderer(); 4022 if (!renderer) 4023 return parentRect; 4024 4025 IntRect rect = parentView->convertFromContainingViewToRenderer(renderer, parentRect); 4026 // Subtract borders and padding 4027 rect.move(-renderer->borderLeft() - renderer->paddingLeft(), 4028 -renderer->borderTop() - renderer->paddingTop()); 4029 return rect; 4030 } 4031 4032 return Widget::convertFromContainingView(parentRect); 4033 } 4034 4035 return parentRect; 4036} 4037 4038IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const 4039{ 4040 if (const ScrollView* parentScrollView = parent()) { 4041 if (parentScrollView->isFrameView()) { 4042 const FrameView* parentView = toFrameView(parentScrollView); 4043 4044 // Get our renderer in the parent view 4045 RenderWidget* renderer = frame().ownerRenderer(); 4046 if (!renderer) 4047 return localPoint; 4048 4049 IntPoint point(localPoint); 4050 4051 // Add borders and padding 4052 point.move(renderer->borderLeft() + renderer->paddingLeft(), 4053 renderer->borderTop() + renderer->paddingTop()); 4054 return parentView->convertFromRendererToContainingView(renderer, point); 4055 } 4056 4057 return Widget::convertToContainingView(localPoint); 4058 } 4059 4060 return localPoint; 4061} 4062 4063IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const 4064{ 4065 if (const ScrollView* parentScrollView = parent()) { 4066 if (parentScrollView->isFrameView()) { 4067 const FrameView* parentView = toFrameView(parentScrollView); 4068 4069 // Get our renderer in the parent view 4070 RenderWidget* renderer = frame().ownerRenderer(); 4071 if (!renderer) 4072 return parentPoint; 4073 4074 IntPoint point = parentView->convertFromContainingViewToRenderer(renderer, parentPoint); 4075 // Subtract borders and padding 4076 point.move(-renderer->borderLeft() - renderer->paddingLeft(), 4077 -renderer->borderTop() - renderer->paddingTop()); 4078 return point; 4079 } 4080 4081 return Widget::convertFromContainingView(parentPoint); 4082 } 4083 4084 return parentPoint; 4085} 4086 4087void FrameView::setTracksRepaints(bool trackRepaints) 4088{ 4089 if (trackRepaints == m_isTrackingRepaints) 4090 return; 4091 4092 // Force layout to flush out any pending repaints. 4093 if (trackRepaints) { 4094 if (frame().document()) 4095 frame().document()->updateLayout(); 4096 } 4097 4098 for (Frame* frame = &m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) { 4099 if (RenderView* renderView = frame->contentRenderer()) 4100 renderView->compositor().setTracksRepaints(trackRepaints); 4101 } 4102 4103 resetTrackedRepaints(); 4104 m_isTrackingRepaints = trackRepaints; 4105} 4106 4107void FrameView::resetTrackedRepaints() 4108{ 4109 m_trackedRepaintRects.clear(); 4110 if (RenderView* renderView = this->renderView()) 4111 renderView->compositor().resetTrackedRepaintRects(); 4112} 4113 4114String FrameView::trackedRepaintRectsAsText() const 4115{ 4116 if (frame().document()) 4117 frame().document()->updateLayout(); 4118 4119 TextStream ts; 4120 if (!m_trackedRepaintRects.isEmpty()) { 4121 ts << "(repaint rects\n"; 4122 for (size_t i = 0; i < m_trackedRepaintRects.size(); ++i) 4123 ts << " (rect " << LayoutUnit(m_trackedRepaintRects[i].x()) << " " << LayoutUnit(m_trackedRepaintRects[i].y()) << " " << LayoutUnit(m_trackedRepaintRects[i].width()) << " " << LayoutUnit(m_trackedRepaintRects[i].height()) << ")\n"; 4124 ts << ")\n"; 4125 } 4126 return ts.release(); 4127} 4128 4129bool FrameView::addScrollableArea(ScrollableArea* scrollableArea) 4130{ 4131 if (!m_scrollableAreas) 4132 m_scrollableAreas = std::make_unique<ScrollableAreaSet>(); 4133 4134 if (m_scrollableAreas->add(scrollableArea).isNewEntry) { 4135 scrollableAreaSetChanged(); 4136 return true; 4137 } 4138 4139 return false; 4140} 4141 4142bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea) 4143{ 4144 if (m_scrollableAreas && m_scrollableAreas->remove(scrollableArea)) { 4145 scrollableAreaSetChanged(); 4146 return true; 4147 } 4148 return false; 4149} 4150 4151bool FrameView::containsScrollableArea(ScrollableArea* scrollableArea) const 4152{ 4153 return m_scrollableAreas && m_scrollableAreas->contains(scrollableArea); 4154} 4155 4156void FrameView::scrollableAreaSetChanged() 4157{ 4158 if (auto* page = frame().page()) { 4159 if (auto* scrollingCoordinator = page->scrollingCoordinator()) 4160 scrollingCoordinator->frameViewNonFastScrollableRegionChanged(this); 4161 } 4162} 4163 4164void FrameView::sendScrollEvent() 4165{ 4166 frame().eventHandler().sendScrollEvent(); 4167 frame().eventHandler().dispatchFakeMouseMoveEventSoon(); 4168} 4169 4170void FrameView::removeChild(Widget* widget) 4171{ 4172 if (widget->isFrameView()) 4173 removeScrollableArea(toFrameView(widget)); 4174 4175 ScrollView::removeChild(widget); 4176} 4177 4178bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) 4179{ 4180 // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views 4181 // should handle wheel events. 4182#if !ENABLE(RUBBER_BANDING) 4183 if (!isScrollable()) 4184 return false; 4185#endif 4186 4187 if (delegatesScrolling()) { 4188 IntSize offset = scrollOffset(); 4189 IntPoint oldPosition = scrollPosition(); 4190 IntSize newOffset = IntSize(offset.width() - wheelEvent.deltaX(), offset.height() - wheelEvent.deltaY()); 4191 if (offset != newOffset) { 4192 ScrollView::scrollTo(newOffset); 4193 scrollPositionChanged(oldPosition, scrollPosition()); 4194 frame().loader().client().didChangeScrollOffset(); 4195 } 4196 return true; 4197 } 4198 4199 // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled. 4200 if (!canHaveScrollbars()) 4201 return false; 4202 4203 if (platformWidget()) 4204 return false; 4205 4206#if ENABLE(ASYNC_SCROLLING) 4207 if (Page* page = frame().page()) { 4208 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { 4209 if (scrollingCoordinator->coordinatesScrollingForFrameView(this)) 4210 return scrollingCoordinator->handleWheelEvent(this, wheelEvent); 4211 } 4212 } 4213#endif 4214 4215 return ScrollableArea::handleWheelEvent(wheelEvent); 4216} 4217 4218 4219bool FrameView::isVerticalDocument() const 4220{ 4221 RenderView* renderView = this->renderView(); 4222 if (!renderView) 4223 return true; 4224 4225 return renderView->style().isHorizontalWritingMode(); 4226} 4227 4228bool FrameView::isFlippedDocument() const 4229{ 4230 RenderView* renderView = this->renderView(); 4231 if (!renderView) 4232 return false; 4233 4234 return renderView->style().isFlippedBlocksWritingMode(); 4235} 4236 4237void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification) 4238{ 4239 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) { 4240 if (FrameView* view = frame->view()) 4241 view->notifyWidgets(notification); 4242 } 4243} 4244 4245AXObjectCache* FrameView::axObjectCache() const 4246{ 4247 if (frame().document()) 4248 return frame().document()->existingAXObjectCache(); 4249 return 0; 4250} 4251 4252#if PLATFORM(IOS) 4253void FrameView::setCustomFixedPositionLayoutRect(const IntRect& rect) 4254{ 4255 if (m_useCustomFixedPositionLayoutRect && m_customFixedPositionLayoutRect == rect) 4256 return; 4257 m_useCustomFixedPositionLayoutRect = true; 4258 m_customFixedPositionLayoutRect = rect; 4259 visibleContentsResized(); 4260} 4261 4262bool FrameView::updateFixedPositionLayoutRect() 4263{ 4264 if (!m_useCustomFixedPositionLayoutRect) 4265 return false; 4266 4267 IntRect newRect; 4268 Page* page = frame().page(); 4269 if (!page || !page->chrome().client().fetchCustomFixedPositionLayoutRect(newRect)) 4270 return false; 4271 4272 if (newRect != m_customFixedPositionLayoutRect) { 4273 m_customFixedPositionLayoutRect = newRect; 4274 setViewportConstrainedObjectsNeedLayout(); 4275 return true; 4276 } 4277 return false; 4278} 4279 4280void FrameView::setCustomSizeForResizeEvent(IntSize customSize) 4281{ 4282 m_useCustomSizeForResizeEvent = true; 4283 m_customSizeForResizeEvent = customSize; 4284 sendResizeEventIfNeeded(); 4285} 4286 4287void FrameView::setScrollVelocity(double horizontalVelocity, double verticalVelocity, double scaleChangeRate, double timestamp) 4288{ 4289 m_horizontalVelocity = horizontalVelocity; 4290 m_verticalVelocity = verticalVelocity; 4291 m_scaleChangeRate = scaleChangeRate; 4292 m_lastVelocityUpdateTime = timestamp; 4293} 4294 4295FloatRect FrameView::computeCoverageRect(double horizontalMargin, double verticalMargin) const 4296{ 4297 FloatRect exposedContentRect = this->exposedContentRect(); 4298 if (!m_speculativeTilingEnabled || memoryPressureHandler().isUnderMemoryPressure()) 4299 return exposedContentRect; 4300 4301 double currentTime = monotonicallyIncreasingTime(); 4302 double timeDelta = currentTime - m_lastVelocityUpdateTime; 4303 4304 FloatRect futureRect = exposedContentRect; 4305 futureRect.setLocation(FloatPoint(futureRect.location().x() + timeDelta * m_horizontalVelocity, futureRect.location().y() + timeDelta * m_verticalVelocity)); 4306 4307 if (m_horizontalVelocity) { 4308 futureRect.setWidth(futureRect.width() + horizontalMargin); 4309 if (m_horizontalVelocity < 0) 4310 futureRect.setX(futureRect.x() - horizontalMargin); 4311 } 4312 4313 if (m_verticalVelocity) { 4314 futureRect.setHeight(futureRect.height() + verticalMargin); 4315 if (m_verticalVelocity < 0) 4316 futureRect.setY(futureRect.y() - verticalMargin); 4317 } 4318 4319 if (m_scaleChangeRate <= 0 && !m_horizontalVelocity && !m_verticalVelocity) { 4320 futureRect.setWidth(futureRect.width() + horizontalMargin); 4321 futureRect.setHeight(futureRect.height() + verticalMargin); 4322 futureRect.setX(futureRect.x() - horizontalMargin / 2); 4323 futureRect.setY(futureRect.y() - verticalMargin / 2); 4324 } 4325 4326 IntSize contentSize = contentsSize(); 4327 if (futureRect.maxX() > contentSize.width()) 4328 futureRect.setX(contentSize.width() - futureRect.width()); 4329 if (futureRect.maxY() > contentSize.height()) 4330 futureRect.setY(contentSize.height() - futureRect.height()); 4331 if (futureRect.x() < 0) 4332 futureRect.setX(0); 4333 if (futureRect.y() < 0) 4334 futureRect.setY(0); 4335 4336 return futureRect; 4337} 4338#endif // PLATFORM(IOS) 4339 4340void FrameView::setScrollingPerformanceLoggingEnabled(bool flag) 4341{ 4342 if (TiledBacking* tiledBacking = this->tiledBacking()) 4343 tiledBacking->setScrollingPerformanceLoggingEnabled(flag); 4344} 4345 4346void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) 4347{ 4348 ScrollableArea::didAddScrollbar(scrollbar, orientation); 4349 if (AXObjectCache* cache = axObjectCache()) 4350 cache->handleScrollbarUpdate(this); 4351} 4352 4353void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) 4354{ 4355 ScrollableArea::willRemoveScrollbar(scrollbar, orientation); 4356 if (AXObjectCache* cache = axObjectCache()) { 4357 cache->remove(scrollbar); 4358 cache->handleScrollbarUpdate(this); 4359 } 4360} 4361 4362void FrameView::addPaintPendingMilestones(LayoutMilestones milestones) 4363{ 4364 m_milestonesPendingPaint |= milestones; 4365} 4366 4367void FrameView::fireLayoutRelatedMilestonesIfNeeded() 4368{ 4369 LayoutMilestones requestedMilestones = 0; 4370 LayoutMilestones milestonesAchieved = 0; 4371 Page* page = frame().page(); 4372 if (page) 4373 requestedMilestones = page->requestedLayoutMilestones(); 4374 4375 if (m_firstLayoutCallbackPending) { 4376 m_firstLayoutCallbackPending = false; 4377 frame().loader().didFirstLayout(); 4378 if (requestedMilestones & DidFirstLayout) 4379 milestonesAchieved |= DidFirstLayout; 4380 if (frame().isMainFrame()) 4381 page->startCountingRelevantRepaintedObjects(); 4382 } 4383 updateIsVisuallyNonEmpty(); 4384 4385 // If the layout was done with pending sheets, we are not in fact visually non-empty yet. 4386 if (m_isVisuallyNonEmpty && !frame().document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) { 4387 m_firstVisuallyNonEmptyLayoutCallbackPending = false; 4388 if (requestedMilestones & DidFirstVisuallyNonEmptyLayout) 4389 milestonesAchieved |= DidFirstVisuallyNonEmptyLayout; 4390 } 4391 4392 if (milestonesAchieved && frame().isMainFrame()) 4393 frame().loader().didLayout(milestonesAchieved); 4394} 4395 4396void FrameView::firePaintRelatedMilestonesIfNeeded() 4397{ 4398 Page* page = frame().page(); 4399 if (!page) 4400 return; 4401 4402 LayoutMilestones milestonesAchieved = 0; 4403 4404 // Make sure the pending paint milestones have actually been requested before we send them. 4405 if (m_milestonesPendingPaint & DidFirstFlushForHeaderLayer) { 4406 if (page->requestedLayoutMilestones() & DidFirstFlushForHeaderLayer) 4407 milestonesAchieved |= DidFirstFlushForHeaderLayer; 4408 } 4409 4410 if (m_milestonesPendingPaint & DidFirstPaintAfterSuppressedIncrementalRendering) { 4411 if (page->requestedLayoutMilestones() & DidFirstPaintAfterSuppressedIncrementalRendering) 4412 milestonesAchieved |= DidFirstPaintAfterSuppressedIncrementalRendering; 4413 } 4414 4415 m_milestonesPendingPaint = 0; 4416 4417 if (milestonesAchieved) 4418 page->mainFrame().loader().didLayout(milestonesAchieved); 4419} 4420 4421void FrameView::setVisualUpdatesAllowedByClient(bool visualUpdatesAllowed) 4422{ 4423 if (m_visualUpdatesAllowedByClient == visualUpdatesAllowed) 4424 return; 4425 4426 m_visualUpdatesAllowedByClient = visualUpdatesAllowed; 4427 4428 frame().document()->setVisualUpdatesAllowedByClient(visualUpdatesAllowed); 4429} 4430 4431void FrameView::setScrollPinningBehavior(ScrollPinningBehavior pinning) 4432{ 4433 m_scrollPinningBehavior = pinning; 4434 4435 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator()) 4436 scrollingCoordinator->setScrollPinningBehavior(pinning); 4437 4438 updateScrollbars(scrollOffset()); 4439} 4440 4441ScrollBehaviorForFixedElements FrameView::scrollBehaviorForFixedElements() const 4442{ 4443 return frame().settings().backgroundShouldExtendBeyondPage() ? StickToViewportBounds : StickToDocumentBounds; 4444} 4445 4446RenderView* FrameView::renderView() const 4447{ 4448 return frame().contentRenderer(); 4449} 4450 4451int FrameView::mapFromLayoutToCSSUnits(LayoutUnit value) const 4452{ 4453 return value / (frame().pageZoomFactor() * frame().frameScaleFactor()); 4454} 4455 4456LayoutUnit FrameView::mapFromCSSToLayoutUnits(int value) const 4457{ 4458 return value * frame().pageZoomFactor() * frame().frameScaleFactor(); 4459} 4460 4461void FrameView::didAddWidgetToRenderTree(Widget& widget) 4462{ 4463 ASSERT(!m_widgetsInRenderTree.contains(&widget)); 4464 m_widgetsInRenderTree.add(&widget); 4465} 4466 4467void FrameView::willRemoveWidgetFromRenderTree(Widget& widget) 4468{ 4469 ASSERT(m_widgetsInRenderTree.contains(&widget)); 4470 m_widgetsInRenderTree.remove(&widget); 4471} 4472 4473static Vector<RefPtr<Widget>> collectAndProtectWidgets(const HashSet<Widget*>& set) 4474{ 4475 Vector<RefPtr<Widget>> widgets; 4476 copyToVector(set, widgets); 4477 return widgets; 4478} 4479 4480void FrameView::updateWidgetPositions() 4481{ 4482 // updateWidgetPosition() can possibly cause layout to be re-entered (via plug-ins running 4483 // scripts in response to NPP_SetWindow, for example), so we need to keep the Widgets 4484 // alive during enumeration. 4485 auto protectedWidgets = collectAndProtectWidgets(m_widgetsInRenderTree); 4486 4487 for (unsigned i = 0, size = protectedWidgets.size(); i < size; ++i) { 4488 if (RenderWidget* renderWidget = RenderWidget::find(protectedWidgets[i].get())) 4489 renderWidget->updateWidgetPosition(); 4490 } 4491} 4492 4493void FrameView::notifyWidgets(WidgetNotification notification) 4494{ 4495 auto protectedWidgets = collectAndProtectWidgets(m_widgetsInRenderTree); 4496 4497 for (unsigned i = 0, size = protectedWidgets.size(); i < size; ++i) 4498 protectedWidgets[i]->notifyWidget(notification); 4499} 4500 4501void FrameView::setExposedRect(FloatRect exposedRect) 4502{ 4503 if (m_exposedRect == exposedRect) 4504 return; 4505 m_exposedRect = exposedRect; 4506 4507 // FIXME: We should support clipping to the exposed rect for subframes as well. 4508 if (!m_frame->isMainFrame()) 4509 return; 4510 if (TiledBacking* tiledBacking = this->tiledBacking()) { 4511 adjustTiledBackingCoverage(); 4512 tiledBacking->setTiledScrollingIndicatorPosition(exposedRect.location()); 4513 } 4514 4515 if (auto* view = renderView()) 4516 view->compositor().scheduleLayerFlush(false /* canThrottle */); 4517} 4518 4519void FrameView::setViewportSizeForCSSViewportUnits(IntSize size) 4520{ 4521 if (m_hasOverrideViewportSize && m_overrideViewportSize == size) 4522 return; 4523 4524 m_overrideViewportSize = size; 4525 m_hasOverrideViewportSize = true; 4526 4527 if (Document* document = m_frame->document()) 4528 document->styleResolverChanged(DeferRecalcStyle); 4529} 4530 4531IntSize FrameView::viewportSizeForCSSViewportUnits() const 4532{ 4533 if (m_hasOverrideViewportSize) 4534 return m_overrideViewportSize; 4535 4536 return visibleContentRectIncludingScrollbars().size(); 4537} 4538 4539} // namespace WebCore 4540