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-2008, 2013-2015 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.
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.
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.
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.
28 #include "FrameView.h"
30 #include "AXObjectCache.h"
31 #include "AnimationController.h"
32 #include "BackForwardController.h"
33 #include "CachedImage.h"
34 #include "CachedResourceLoader.h"
36 #include "ChromeClient.h"
37 #include "DOMWindow.h"
38 #include "DebugPageOverlays.h"
39 #include "DocumentMarkerController.h"
40 #include "EventHandler.h"
41 #include "EventNames.h"
42 #include "FloatRect.h"
43 #include "FocusController.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameSelection.h"
47 #include "FrameTree.h"
48 #include "GraphicsContext.h"
49 #include "HTMLBodyElement.h"
50 #include "HTMLDocument.h"
51 #include "HTMLEmbedElement.h"
52 #include "HTMLFrameElement.h"
53 #include "HTMLFrameSetElement.h"
54 #include "HTMLHtmlElement.h"
55 #include "HTMLIFrameElement.h"
56 #include "HTMLNames.h"
57 #include "HTMLObjectElement.h"
58 #include "HTMLPlugInImageElement.h"
59 #include "ImageDocument.h"
60 #include "InspectorClient.h"
61 #include "InspectorController.h"
62 #include "InspectorInstrumentation.h"
64 #include "MainFrame.h"
65 #include "MemoryCache.h"
66 #include "MemoryPressureHandler.h"
67 #include "OverflowEvent.h"
69 #include "PageCache.h"
70 #include "PageOverlayController.h"
71 #include "ProgressTracker.h"
72 #include "RenderEmbeddedObject.h"
73 #include "RenderFullScreen.h"
74 #include "RenderIFrame.h"
75 #include "RenderInline.h"
76 #include "RenderLayer.h"
77 #include "RenderLayerBacking.h"
78 #include "RenderLayerCompositor.h"
79 #include "RenderSVGRoot.h"
80 #include "RenderScrollbar.h"
81 #include "RenderScrollbarPart.h"
82 #include "RenderStyle.h"
83 #include "RenderText.h"
84 #include "RenderTheme.h"
85 #include "RenderView.h"
86 #include "RenderWidget.h"
87 #include "SVGDocument.h"
88 #include "SVGSVGElement.h"
89 #include "ScriptedAnimationController.h"
90 #include "ScrollAnimator.h"
91 #include "ScrollingCoordinator.h"
93 #include "StyleResolver.h"
94 #include "StyleScope.h"
95 #include "TextResourceDecoder.h"
96 #include "TextStream.h"
97 #include "TiledBacking.h"
98 #include "WheelEventTestTrigger.h"
100 #include <wtf/CurrentTime.h>
102 #include <wtf/SetForScope.h>
103 #include <wtf/SystemTracing.h>
105 #if USE(COORDINATED_GRAPHICS)
106 #include "TiledBackingStore.h"
109 #if ENABLE(CSS_SCROLL_SNAP)
110 #include "AxisScrollSnapOffsets.h"
114 #include "DocumentLoader.h"
115 #include "LegacyTileCache.h"
120 using namespace HTMLNames;
122 double FrameView::sCurrentPaintTimeStamp = 0.0;
124 // The maximum number of updateEmbeddedObjects iterations that should be done before returning.
125 static const unsigned maxUpdateEmbeddedObjectsIterations = 2;
127 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
129 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
130 if (didFullRepaint) {
131 flags &= ~RenderLayer::CheckForRepaint;
132 flags |= RenderLayer::NeedsFullRepaintInBacking;
134 if (isRelayoutingSubtree && layer->enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers))
135 flags |= RenderLayer::UpdatePagination;
139 Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style)
141 EOverflow overflow = style.overflowY();
142 if (overflow != OPAGEDX && overflow != OPAGEDY)
143 return Pagination::Unpaginated;
145 bool isHorizontalWritingMode = style.isHorizontalWritingMode();
146 TextDirection textDirection = style.direction();
147 WritingMode writingMode = style.writingMode();
149 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode
150 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode
151 // is vertical, then the direction of the verticality dictates the choice.
152 if (overflow == OPAGEDX) {
153 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode)
154 return Pagination::LeftToRightPaginated;
155 return Pagination::RightToLeftPaginated;
158 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode
159 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode
160 // is vertical, then we use TextDirection to choose between those options.
161 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL))
162 return Pagination::TopToBottomPaginated;
163 return Pagination::BottomToTopPaginated;
166 class SubtreeLayoutStateMaintainer {
168 SubtreeLayoutStateMaintainer(RenderElement* subtreeLayoutRoot)
169 : m_layoutRoot(subtreeLayoutRoot)
172 RenderView& view = m_layoutRoot->view();
173 view.pushLayoutState(*m_layoutRoot);
174 if (shouldDisableLayoutStateForSubtree()) {
175 view.disableLayoutState();
176 m_didDisableLayoutState = true;
181 ~SubtreeLayoutStateMaintainer()
184 RenderView& view = m_layoutRoot->view();
185 view.popLayoutState(*m_layoutRoot);
186 if (m_didDisableLayoutState)
187 view.enableLayoutState();
191 bool shouldDisableLayoutStateForSubtree()
193 for (auto* renderer = m_layoutRoot; renderer; renderer = renderer->container()) {
194 if (renderer->hasTransform() || renderer->hasReflection())
201 RenderElement* m_layoutRoot { nullptr };
202 bool m_didDisableLayoutState { false };
206 class RenderTreeNeedsLayoutChecker {
208 RenderTreeNeedsLayoutChecker(const RenderElement& layoutRoot)
209 : m_layoutRoot(layoutRoot)
213 ~RenderTreeNeedsLayoutChecker()
215 auto reportNeedsLayoutError = [] (const RenderObject& renderer) {
216 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "post-layout: dirty renderer(s)");
217 renderer.showRenderTreeForThis();
218 ASSERT_NOT_REACHED();
221 if (m_layoutRoot.needsLayout()) {
222 reportNeedsLayoutError(m_layoutRoot);
226 for (auto* descendant = m_layoutRoot.firstChild(); descendant; descendant = descendant->nextInPreOrder(&m_layoutRoot)) {
227 if (!descendant->needsLayout())
230 reportNeedsLayoutError(*descendant);
236 const RenderElement& m_layoutRoot;
240 FrameView::FrameView(Frame& frame)
242 , m_canHaveScrollbars(true)
243 , m_layoutTimer(*this, &FrameView::layoutTimerFired)
244 , m_layoutPhase(OutsideLayout)
245 , m_inSynchronousPostLayout(false)
246 , m_postLayoutTasksTimer(*this, &FrameView::performPostLayoutTasks)
247 , m_updateEmbeddedObjectsTimer(*this, &FrameView::updateEmbeddedObjectsTimerFired)
248 , m_isTransparent(false)
249 , m_baseBackgroundColor(Color::white)
250 , m_mediaType("screen")
251 , m_overflowStatusDirty(true)
252 , m_wasScrolledByUser(false)
253 , m_inProgrammaticScroll(false)
254 , m_safeToPropagateScrollToParent(true)
255 , m_delayedScrollEventTimer(*this, &FrameView::sendScrollEvent)
256 , m_isTrackingRepaints(false)
257 , m_shouldUpdateWhileOffscreen(true)
258 , m_deferSetNeedsLayoutCount(0)
259 , m_setNeedsLayoutWasDeferred(false)
260 , m_speculativeTilingEnabled(false)
261 , m_speculativeTilingEnableTimer(*this, &FrameView::speculativeTilingEnableTimerFired)
263 , m_useCustomFixedPositionLayoutRect(false)
264 , m_useCustomSizeForResizeEvent(false)
266 , m_hasOverrideViewportSize(false)
267 , m_shouldAutoSize(false)
268 , m_inAutoSize(false)
269 , m_didRunAutosize(false)
270 , m_autoSizeFixedMinimumHeight(0)
273 , m_milestonesPendingPaint(0)
274 , m_visualUpdatesAllowedByClient(true)
275 , m_hasFlippedBlockRenderers(false)
276 , m_scrollPinningBehavior(DoNotPin)
280 #if ENABLE(RUBBER_BANDING)
281 ScrollElasticity verticalElasticity = ScrollElasticityNone;
282 ScrollElasticity horizontalElasticity = ScrollElasticityNone;
283 if (m_frame->isMainFrame()) {
284 verticalElasticity = m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed;
285 horizontalElasticity = m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed;
286 } else if (m_frame->settings().rubberBandingForSubScrollableRegionsEnabled()) {
287 verticalElasticity = ScrollElasticityAutomatic;
288 horizontalElasticity = ScrollElasticityAutomatic;
291 ScrollableArea::setVerticalScrollElasticity(verticalElasticity);
292 ScrollableArea::setHorizontalScrollElasticity(horizontalElasticity);
296 Ref<FrameView> FrameView::create(Frame& frame)
298 Ref<FrameView> view = adoptRef(*new FrameView(frame));
303 Ref<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
305 Ref<FrameView> view = adoptRef(*new FrameView(frame));
306 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
311 FrameView::~FrameView()
313 if (m_postLayoutTasksTimer.isActive())
314 m_postLayoutTasksTimer.stop();
316 removeFromAXObjectCache();
319 // Custom scrollbars should already be destroyed at this point
320 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
321 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
323 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
324 setHasVerticalScrollbar(false);
326 ASSERT(!m_scrollCorner);
328 ASSERT(frame().view() != this || !frame().contentRenderer());
331 void FrameView::reset()
333 m_cannotBlitToWindow = false;
334 m_isOverlapped = false;
335 m_contentIsOpaque = false;
336 m_layoutTimer.stop();
337 m_layoutRoot = nullptr;
338 m_delayedLayout = false;
339 m_needsFullRepaint = true;
340 m_layoutSchedulingEnabled = true;
341 m_layoutPhase = OutsideLayout;
342 m_inSynchronousPostLayout = false;
344 m_nestedLayoutCount = 0;
345 m_postLayoutTasksTimer.stop();
346 m_updateEmbeddedObjectsTimer.stop();
347 m_firstLayout = true;
348 m_firstLayoutCallbackPending = false;
349 m_wasScrolledByUser = false;
350 m_safeToPropagateScrollToParent = true;
351 m_delayedScrollEventTimer.stop();
352 m_lastViewportSize = IntSize();
353 m_lastZoomFactor = 1.0f;
354 m_isTrackingRepaints = false;
355 m_trackedRepaintRects.clear();
357 m_paintBehavior = PaintBehaviorNormal;
358 m_isPainting = false;
359 m_visuallyNonEmptyCharacterCount = 0;
360 m_visuallyNonEmptyPixelCount = 0;
361 m_isVisuallyNonEmpty = false;
362 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
363 m_needsDeferredScrollbarsUpdate = false;
364 m_maintainScrollPositionAnchor = nullptr;
367 void FrameView::removeFromAXObjectCache()
369 if (AXObjectCache* cache = axObjectCache()) {
370 if (HTMLFrameOwnerElement* owner = frame().ownerElement())
371 cache->childrenChanged(owner->renderer());
376 void FrameView::resetScrollbars()
378 // Reset the document's scrollbars back to our defaults before we yield the floor.
379 m_firstLayout = true;
380 setScrollbarsSuppressed(true);
381 if (m_canHaveScrollbars)
382 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
384 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
385 setScrollbarsSuppressed(false);
388 void FrameView::resetScrollbarsAndClearContentsSize()
392 setScrollbarsSuppressed(true);
393 setContentsSize(IntSize());
394 setScrollbarsSuppressed(false);
397 void FrameView::init()
401 m_margins = LayoutSize(-1, -1); // undefined
402 m_size = LayoutSize();
404 // Propagate the marginwidth/height and scrolling modes to the view.
405 Element* ownerElement = frame().ownerElement();
406 if (is<HTMLFrameElementBase>(ownerElement)) {
407 HTMLFrameElementBase& frameElement = downcast<HTMLFrameElementBase>(*ownerElement);
408 if (frameElement.scrollingMode() == ScrollbarAlwaysOff)
409 setCanHaveScrollbars(false);
410 LayoutUnit marginWidth = frameElement.marginWidth();
411 LayoutUnit marginHeight = frameElement.marginHeight();
412 if (marginWidth != -1)
413 setMarginWidth(marginWidth);
414 if (marginHeight != -1)
415 setMarginHeight(marginHeight);
418 Page* page = frame().page();
419 if (page && page->chrome().client().shouldPaintEntireContents())
420 setPaintsEntireContents(true);
423 void FrameView::prepareForDetach()
425 detachCustomScrollbars();
426 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
427 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
428 removeFromAXObjectCache();
430 if (frame().page()) {
431 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
432 scrollingCoordinator->willDestroyScrollableArea(*this);
436 void FrameView::detachCustomScrollbars()
438 Scrollbar* horizontalBar = horizontalScrollbar();
439 if (horizontalBar && horizontalBar->isCustomScrollbar())
440 setHasHorizontalScrollbar(false);
442 Scrollbar* verticalBar = verticalScrollbar();
443 if (verticalBar && verticalBar->isCustomScrollbar())
444 setHasVerticalScrollbar(false);
446 m_scrollCorner = nullptr;
449 void FrameView::recalculateScrollbarOverlayStyle()
451 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
452 WTF::Optional<ScrollbarOverlayStyle> clientOverlayStyle = frame().page() ? frame().page()->chrome().client().preferredScrollbarOverlayStyle() : ScrollbarOverlayStyleDefault;
453 if (clientOverlayStyle) {
454 if (clientOverlayStyle.value() != oldOverlayStyle)
455 setScrollbarOverlayStyle(clientOverlayStyle.value());
459 ScrollbarOverlayStyle computedOverlayStyle = ScrollbarOverlayStyleDefault;
461 Color backgroundColor = documentBackgroundColor();
462 if (backgroundColor.isValid()) {
463 // Reduce the background color from RGB to a lightness value
464 // and determine which scrollbar style to use based on a lightness
466 double hue, saturation, lightness;
467 backgroundColor.getHSL(hue, saturation, lightness);
468 if (lightness <= .5 && backgroundColor.isVisible())
469 computedOverlayStyle = ScrollbarOverlayStyleLight;
472 if (oldOverlayStyle != computedOverlayStyle)
473 setScrollbarOverlayStyle(computedOverlayStyle);
476 void FrameView::clear()
478 setCanBlitOnScroll(true);
482 setScrollbarsSuppressed(true);
485 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
486 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
487 if (LegacyTileCache* tileCache = legacyTileCache())
488 tileCache->setTilingMode(LegacyTileCache::Disabled);
493 void FrameView::didReplaceMultipartContent()
495 // Re-enable tile updates that were disabled in clear().
496 if (LegacyTileCache* tileCache = legacyTileCache())
497 tileCache->setTilingMode(LegacyTileCache::Normal);
501 bool FrameView::didFirstLayout() const
503 return !m_firstLayout;
506 void FrameView::invalidateRect(const IntRect& rect)
509 if (HostWindow* window = hostWindow())
510 window->invalidateContentsAndRootView(rect);
514 RenderWidget* renderer = frame().ownerRenderer();
518 IntRect repaintRect = rect;
519 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
520 renderer->borderTop() + renderer->paddingTop());
521 renderer->repaintRectangle(repaintRect);
524 void FrameView::setFrameRect(const IntRect& newRect)
526 Ref<FrameView> protectedThis(*this);
527 IntRect oldRect = frameRect();
528 if (newRect == oldRect)
531 ScrollView::setFrameRect(newRect);
533 updateScrollableAreaSet();
535 if (RenderView* renderView = this->renderView()) {
536 if (renderView->usesCompositing())
537 renderView->compositor().frameViewDidChangeSize();
540 if (frame().isMainFrame())
541 frame().mainFrame().pageOverlayController().didChangeViewSize();
543 viewportContentsChanged();
546 #if ENABLE(REQUEST_ANIMATION_FRAME)
547 bool FrameView::scheduleAnimation()
549 if (HostWindow* window = hostWindow()) {
550 window->scheduleAnimation();
557 void FrameView::setMarginWidth(LayoutUnit w)
559 // make it update the rendering area when set
560 m_margins.setWidth(w);
563 void FrameView::setMarginHeight(LayoutUnit h)
565 // make it update the rendering area when set
566 m_margins.setHeight(h);
569 bool FrameView::frameFlatteningEnabled() const
571 return frame().settings().frameFlatteningEnabled();
574 bool FrameView::isFrameFlatteningValidForThisFrame() const
576 if (!frameFlatteningEnabled())
579 HTMLFrameOwnerElement* owner = frame().ownerElement();
583 // Frame flattening is valid only for <frame> and <iframe>.
584 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
587 bool FrameView::avoidScrollbarCreation() const
589 // with frame flattening no subframe can have scrollbars
590 // but we also cannot turn scrollbars off as we determine
591 // our flattening policy using that.
592 return isFrameFlatteningValidForThisFrame();
595 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
597 m_canHaveScrollbars = canHaveScrollbars;
598 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
601 void FrameView::updateCanHaveScrollbars()
605 scrollbarModes(hMode, vMode);
606 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
607 setCanHaveScrollbars(false);
609 setCanHaveScrollbars(true);
612 Ref<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
614 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
615 return ScrollView::createScrollbar(orientation);
617 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
618 Document* doc = frame().document();
620 // Try the <body> element first as a scrollbar source.
621 HTMLElement* body = doc ? doc->bodyOrFrameset() : nullptr;
622 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
623 return RenderScrollbar::createCustomScrollbar(*this, orientation, body);
625 // If the <body> didn't have a custom style, then the root element might.
626 Element* docElement = doc ? doc->documentElement() : nullptr;
627 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
628 return RenderScrollbar::createCustomScrollbar(*this, orientation, docElement);
630 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
631 RenderWidget* frameRenderer = frame().ownerRenderer();
632 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
633 return RenderScrollbar::createCustomScrollbar(*this, orientation, nullptr, &frame());
635 // Nobody set a custom style, so we just use a native scrollbar.
636 return ScrollView::createScrollbar(orientation);
639 void FrameView::setContentsSize(const IntSize& size)
641 if (size == contentsSize())
644 m_deferSetNeedsLayoutCount++;
646 ScrollView::setContentsSize(size);
649 Page* page = frame().page();
653 updateScrollableAreaSet();
655 page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
657 if (frame().isMainFrame()) {
658 frame().mainFrame().pageOverlayController().didChangeDocumentSize();
659 PageCache::singleton().markPagesForContentsSizeChanged(*page);
662 ASSERT(m_deferSetNeedsLayoutCount);
663 m_deferSetNeedsLayoutCount--;
665 if (!m_deferSetNeedsLayoutCount)
666 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
669 void FrameView::adjustViewSize()
671 RenderView* renderView = this->renderView();
675 ASSERT(frame().view() == this);
677 const IntRect rect = renderView->documentRect();
678 const IntSize& size = rect.size();
679 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
681 LOG_WITH_STREAM(Layout, stream << "FrameView " << this << " adjustViewSize: unscaled document rect changed to " << renderView->unscaledDocumentRect() << " (scaled to " << size << ")");
683 setContentsSize(size);
686 void FrameView::applyOverflowToViewport(const RenderElement& renderer, ScrollbarMode& hMode, ScrollbarMode& vMode)
688 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
689 // overflow:hidden and overflow:scroll on <body> as applying to the document's
690 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
691 // use the root element.
693 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
694 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
697 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
699 EOverflow overflowX = renderer.style().overflowX();
700 EOverflow overflowY = renderer.style().overflowY();
702 if (is<RenderSVGRoot>(renderer)) {
703 // FIXME: evaluate if we can allow overflow for these cases too.
704 // Overflow is always hidden when stand-alone SVG documents are embedded.
705 if (downcast<RenderSVGRoot>(renderer).isEmbeddedThroughFrameContainingSVGDocument()) {
714 hMode = ScrollbarAuto;
716 hMode = ScrollbarAlwaysOff;
719 hMode = ScrollbarAlwaysOn;
722 hMode = ScrollbarAuto;
725 // Don't set it at all.
732 vMode = ScrollbarAuto;
734 vMode = ScrollbarAlwaysOff;
737 vMode = ScrollbarAlwaysOn;
740 vMode = ScrollbarAuto;
743 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
748 void FrameView::applyPaginationToViewport()
750 Document* document = frame().document();
751 auto* documentElement = document->documentElement();
752 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
753 RenderElement* documentOrBodyRenderer = documentRenderer;
754 auto* body = document->body();
755 if (body && body->renderer())
756 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(*documentElement) ? body->renderer() : documentRenderer;
758 Pagination pagination;
760 if (!documentOrBodyRenderer) {
761 setPagination(pagination);
765 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
766 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
767 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
768 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
771 setPagination(pagination);
774 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
776 m_viewportRendererType = ViewportRendererType::None;
778 const HTMLFrameOwnerElement* owner = frame().ownerElement();
779 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
780 hMode = ScrollbarAlwaysOff;
781 vMode = ScrollbarAlwaysOff;
785 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
786 hMode = ScrollbarAuto;
787 vMode = ScrollbarAuto;
789 hMode = ScrollbarAlwaysOff;
790 vMode = ScrollbarAlwaysOff;
796 auto* document = frame().document();
800 auto* documentElement = document->documentElement();
801 if (!documentElement)
804 auto* bodyOrFrameset = document->bodyOrFrameset();
805 auto* rootRenderer = documentElement->renderer();
806 if (!bodyOrFrameset || !bodyOrFrameset->renderer()) {
808 applyOverflowToViewport(*rootRenderer, hMode, vMode);
809 m_viewportRendererType = ViewportRendererType::Document;
814 if (is<HTMLFrameSetElement>(*bodyOrFrameset) && !frameFlatteningEnabled()) {
815 vMode = ScrollbarAlwaysOff;
816 hMode = ScrollbarAlwaysOff;
820 if (is<HTMLBodyElement>(*bodyOrFrameset) && rootRenderer) {
821 // It's sufficient to just check the X overflow,
822 // since it's illegal to have visible in only one direction.
823 if (rootRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(documentElement)) {
824 auto* bodyRenderer = bodyOrFrameset->renderer();
826 applyOverflowToViewport(*bodyRenderer, hMode, vMode);
827 m_viewportRendererType = ViewportRendererType::Body;
830 applyOverflowToViewport(*rootRenderer, hMode, vMode);
831 m_viewportRendererType = ViewportRendererType::Document;
836 void FrameView::willRecalcStyle()
838 RenderView* renderView = this->renderView();
842 renderView->compositor().willRecalcStyle();
845 bool FrameView::updateCompositingLayersAfterStyleChange()
847 RenderView* renderView = this->renderView();
851 // If we expect to update compositing after an incipient layout, don't do so here.
852 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
855 return renderView->compositor().didRecalcStyleWithNoPendingLayout();
858 void FrameView::updateCompositingLayersAfterLayout()
860 RenderView* renderView = this->renderView();
864 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
865 renderView->compositor().cacheAcceleratedCompositingFlags();
866 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
869 void FrameView::clearBackingStores()
871 RenderView* renderView = this->renderView();
875 RenderLayerCompositor& compositor = renderView->compositor();
876 ASSERT(compositor.inCompositingMode());
877 compositor.enableCompositingMode(false);
878 compositor.clearBackingForAllLayers();
881 void FrameView::restoreBackingStores()
883 RenderView* renderView = this->renderView();
887 RenderLayerCompositor& compositor = renderView->compositor();
888 compositor.enableCompositingMode(true);
889 compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
892 GraphicsLayer* FrameView::layerForScrolling() const
894 RenderView* renderView = this->renderView();
897 return renderView->compositor().scrollLayer();
900 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
902 RenderView* renderView = this->renderView();
905 return renderView->compositor().layerForHorizontalScrollbar();
908 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
910 RenderView* renderView = this->renderView();
913 return renderView->compositor().layerForVerticalScrollbar();
916 GraphicsLayer* FrameView::layerForScrollCorner() const
918 RenderView* renderView = this->renderView();
921 return renderView->compositor().layerForScrollCorner();
924 TiledBacking* FrameView::tiledBacking() const
926 RenderView* renderView = this->renderView();
930 RenderLayerBacking* backing = renderView->layer()->backing();
934 return backing->graphicsLayer()->tiledBacking();
937 uint64_t FrameView::scrollLayerID() const
939 RenderView* renderView = this->renderView();
943 RenderLayerBacking* backing = renderView->layer()->backing();
947 return backing->scrollingNodeIDForRole(Scrolling);
950 ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
952 RenderView* renderView = this->renderView();
956 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
959 #if ENABLE(RUBBER_BANDING)
960 GraphicsLayer* FrameView::layerForOverhangAreas() const
962 RenderView* renderView = this->renderView();
965 return renderView->compositor().layerForOverhangAreas();
968 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
970 RenderView* renderView = this->renderView();
974 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
977 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
979 RenderView* renderView = this->renderView();
983 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
986 #endif // ENABLE(RUBBER_BANDING)
988 #if ENABLE(CSS_SCROLL_SNAP)
989 void FrameView::updateSnapOffsets()
991 if (!frame().document())
994 // FIXME: Should we allow specifying snap points through <html> tags too?
995 HTMLElement* body = frame().document()->bodyOrFrameset();
996 if (!renderView() || !body || !body->renderer())
999 updateSnapOffsetsForScrollableArea(*this, *body, *renderView(), body->renderer()->style());
1002 bool FrameView::isScrollSnapInProgress() const
1004 if (scrollbarsSuppressed())
1007 // If the scrolling thread updates the scroll position for this FrameView, then we should return
1008 // ScrollingCoordinator::isScrollSnapInProgress().
1009 if (Page* page = frame().page()) {
1010 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
1011 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this))
1012 return scrollingCoordinator->isScrollSnapInProgress();
1016 // If the main thread updates the scroll position for this FrameView, we should return
1017 // ScrollAnimator::isScrollSnapInProgress().
1018 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1019 return scrollAnimator->isScrollSnapInProgress();
1024 void FrameView::updateScrollingCoordinatorScrollSnapProperties() const
1026 renderView()->compositor().updateScrollSnapPropertiesWithFrameView(*this);
1030 bool FrameView::flushCompositingStateForThisFrame(const Frame& rootFrameForFlush)
1032 RenderView* renderView = this->renderView();
1034 return true; // We don't want to keep trying to update layers if we have no renderer.
1036 ASSERT(frame().view() == this);
1038 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
1039 // layer content to occur before layout has happened, which will cause paintContents() to bail.
1044 if (LegacyTileCache* tileCache = legacyTileCache())
1045 tileCache->doPendingRepaints();
1048 renderView->compositor().flushPendingLayerChanges(&rootFrameForFlush == m_frame.ptr());
1052 void FrameView::setNeedsOneShotDrawingSynchronization()
1054 if (Page* page = frame().page())
1055 page->chrome().client().setNeedsOneShotDrawingSynchronization();
1058 GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
1060 // To find the Widget that corresponds with platformWidget we have to do a linear
1061 // search of our child widgets.
1062 Widget* foundWidget = nullptr;
1063 for (auto& widget : children()) {
1064 if (widget->platformWidget() != platformWidget)
1066 foundWidget = widget.get();
1073 auto* renderWidget = RenderWidget::find(foundWidget);
1077 RenderLayer* widgetLayer = renderWidget->layer();
1078 if (!widgetLayer || !widgetLayer->isComposited())
1081 return widgetLayer->backing()->parentForSublayers();
1084 void FrameView::scheduleLayerFlushAllowingThrottling()
1086 RenderView* view = this->renderView();
1089 view->compositor().scheduleLayerFlush(true /* canThrottle */);
1092 LayoutRect FrameView::fixedScrollableAreaBoundsInflatedForScrolling(const LayoutRect& uninflatedBounds) const
1094 LayoutPoint scrollPosition;
1095 LayoutSize topLeftExpansion;
1096 LayoutSize bottomRightExpansion;
1098 if (frame().settings().visualViewportEnabled()) {
1099 // FIXME: this is wrong under zooming; uninflatedBounds is scaled but the scroll positions are not.
1100 scrollPosition = layoutViewportRect().location();
1101 topLeftExpansion = scrollPosition - unscaledMinimumScrollPosition();
1102 bottomRightExpansion = unscaledMaximumScrollPosition() - scrollPosition;
1104 scrollPosition = scrollPositionRespectingCustomFixedPosition();
1105 topLeftExpansion = scrollPosition - minimumScrollPosition();
1106 bottomRightExpansion = maximumScrollPosition() - scrollPosition;
1109 return LayoutRect(uninflatedBounds.location() - topLeftExpansion, uninflatedBounds.size() + topLeftExpansion + bottomRightExpansion);
1112 LayoutPoint FrameView::scrollPositionRespectingCustomFixedPosition() const
1115 if (!frame().settings().visualViewportEnabled())
1116 return useCustomFixedPositionLayoutRect() ? customFixedPositionLayoutRect().location() : scrollPosition();
1119 return scrollPositionForFixedPosition();
1122 void FrameView::setHeaderHeight(int headerHeight)
1125 ASSERT(frame().isMainFrame());
1126 m_headerHeight = headerHeight;
1128 if (RenderView* renderView = this->renderView())
1129 renderView->setNeedsLayout();
1132 void FrameView::setFooterHeight(int footerHeight)
1135 ASSERT(frame().isMainFrame());
1136 m_footerHeight = footerHeight;
1138 if (RenderView* renderView = this->renderView())
1139 renderView->setNeedsLayout();
1142 float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const
1144 if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset)
1145 return platformTopContentInset();
1147 if (!frame().isMainFrame())
1150 Page* page = frame().page();
1151 return page ? page->topContentInset() : 0;
1154 void FrameView::topContentInsetDidChange(float newTopContentInset)
1156 RenderView* renderView = this->renderView();
1160 if (platformWidget())
1161 platformSetTopContentInset(newTopContentInset);
1165 updateScrollbars(scrollPosition());
1166 if (renderView->usesCompositing())
1167 renderView->compositor().frameViewDidChangeSize();
1169 if (TiledBacking* tiledBacking = this->tiledBacking())
1170 tiledBacking->setTopContentInset(newTopContentInset);
1173 void FrameView::topContentDirectionDidChange()
1175 m_needsDeferredScrollbarsUpdate = true;
1178 void FrameView::handleDeferredScrollbarsUpdateAfterDirectionChange()
1180 if (!m_needsDeferredScrollbarsUpdate)
1183 m_needsDeferredScrollbarsUpdate = false;
1185 ASSERT(m_layoutPhase == InPostLayerPositionsUpdatedAfterLayout);
1186 updateScrollbars(scrollPosition());
1187 positionScrollbarLayers();
1190 bool FrameView::hasCompositedContent() const
1192 if (RenderView* renderView = this->renderView())
1193 return renderView->compositor().inCompositingMode();
1197 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
1198 void FrameView::enterCompositingMode()
1200 if (RenderView* renderView = this->renderView()) {
1201 renderView->compositor().enableCompositingMode();
1203 renderView->compositor().scheduleCompositingLayerUpdate();
1207 bool FrameView::isEnclosedInCompositingLayer() const
1209 auto frameOwnerRenderer = frame().ownerRenderer();
1210 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1213 if (FrameView* parentView = parentFrameView())
1214 return parentView->isEnclosedInCompositingLayer();
1218 bool FrameView::flushCompositingStateIncludingSubframes()
1220 InspectorInstrumentation::willComposite(frame());
1222 bool allFramesFlushed = flushCompositingStateForThisFrame(frame());
1224 for (Frame* child = frame().tree().firstRenderedChild(); child; child = child->tree().traverseNextRendered(m_frame.ptr())) {
1227 bool flushed = child->view()->flushCompositingStateForThisFrame(frame());
1228 allFramesFlushed &= flushed;
1230 return allFramesFlushed;
1233 bool FrameView::isSoftwareRenderable() const
1235 RenderView* renderView = this->renderView();
1236 return !renderView || !renderView->compositor().has3DContent();
1239 void FrameView::setIsInWindow(bool isInWindow)
1241 if (RenderView* renderView = this->renderView())
1242 renderView->setIsInWindow(isInWindow);
1245 inline void FrameView::forceLayoutParentViewIfNeeded()
1247 RenderWidget* ownerRenderer = frame().ownerRenderer();
1251 RenderBox* contentBox = embeddedContentBox();
1255 auto& svgRoot = downcast<RenderSVGRoot>(*contentBox);
1256 if (svgRoot.everHadLayout() && !svgRoot.needsLayout())
1259 LOG(Layout, "FrameView %p forceLayoutParentViewIfNeeded scheduling layout on parent FrameView %p", this, &ownerRenderer->view().frameView());
1261 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1262 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1263 // embeddedContentBox() returns nullptr, as long as the embedded document isn't loaded yet. Before
1264 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1265 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1266 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1267 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1269 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1270 ownerRenderer->view().frameView().scheduleRelayout();
1273 void FrameView::layout(bool allowSubtree)
1275 LOG(Layout, "FrameView %p (%dx%d) layout, main frameview %d, allowSubtree=%d", this, size().width(), size().height(), frame().isMainFrame(), allowSubtree);
1276 if (isInRenderTreeLayout()) {
1277 LOG(Layout, " in layout, bailing");
1281 if (layoutDisallowed()) {
1282 LOG(Layout, " layout is disallowed, bailing");
1286 // Protect the view from being deleted during layout (in recalcStyle).
1287 Ref<FrameView> protectedThis(*this);
1289 // Many of the tasks performed during layout can cause this function to be re-entered,
1290 // so save the layout phase now and restore it on exit.
1291 SetForScope<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1293 // Every scroll that happens during layout is programmatic.
1294 SetForScope<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1296 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1298 if (inChildFrameLayoutWithFrameFlattening) {
1299 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1300 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1301 if (!root || !root->needsLayout())
1305 TraceScope tracingScope(LayoutStart, LayoutEnd);
1308 if (updateFixedPositionLayoutRect())
1309 allowSubtree = false;
1312 m_layoutTimer.stop();
1313 m_delayedLayout = false;
1314 m_setNeedsLayoutWasDeferred = false;
1316 // we shouldn't enter layout() while painting
1317 ASSERT(!isPainting());
1321 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(frame());
1322 AnimationUpdateBlock animationUpdateBlock(&frame().animation());
1324 if (!allowSubtree && m_layoutRoot)
1325 convertSubtreeLayoutToFullLayout();
1327 ASSERT(frame().view() == this);
1328 ASSERT(frame().document());
1330 Document& document = *frame().document();
1331 ASSERT(document.pageCacheState() == Document::NotInPageCache);
1334 SetForScope<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1336 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1337 // This is a new top-level layout. If there are any remaining tasks from the previous
1338 // layout, finish them now.
1339 SetForScope<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1340 performPostLayoutTasks();
1343 m_layoutPhase = InPreLayoutStyleUpdate;
1345 // Viewport-dependent media queries may cause us to need completely different style information.
1346 auto* styleResolver = document.styleScope().resolverIfExists();
1347 if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) {
1348 LOG(Layout, " hasMediaQueriesAffectedByViewportChange, enqueueing style recalc");
1349 document.styleScope().didChangeStyleSheetEnvironment();
1350 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1351 InspectorInstrumentation::mediaQueryResultChanged(document);
1353 document.evaluateMediaQueryList();
1355 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1356 // take care of that now.
1357 applyPaginationToViewport();
1359 // Always ensure our style info is up-to-date. This can happen in situations where
1360 // the layout beats any sort of style recalc update that needs to occur.
1361 document.updateStyleIfNeeded();
1362 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1363 // so there's no point to continuing to layout
1367 // Close block here so we can set up the font cache purge preventer, which we will still
1368 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1369 // The next block sets m_layoutSchedulingEnabled back to false once again.
1372 m_layoutPhase = InPreLayout;
1374 RenderLayer* layer = nullptr;
1375 bool subtree = false;
1376 RenderElement* root = nullptr;
1378 ++m_nestedLayoutCount;
1381 SetForScope<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1383 autoSizeIfEnabled();
1385 root = m_layoutRoot ? m_layoutRoot : document.renderView();
1388 subtree = m_layoutRoot;
1390 if (!m_layoutRoot) {
1391 auto* body = document.bodyOrFrameset();
1392 if (body && body->renderer()) {
1393 if (is<HTMLFrameSetElement>(*body) && !frameFlatteningEnabled()) {
1394 body->renderer()->setChildNeedsLayout();
1395 } else if (is<HTMLBodyElement>(*body)) {
1396 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport())
1397 body->renderer()->setChildNeedsLayout();
1401 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1402 if (m_firstLayout && !frame().ownerElement())
1403 printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count());
1407 m_needsFullRepaint = !subtree && (m_firstLayout || downcast<RenderView>(*root).printing());
1410 ScrollbarMode hMode;
1411 ScrollbarMode vMode;
1412 calculateScrollbarModesForLayout(hMode, vMode);
1414 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1415 if (m_firstLayout) {
1416 setScrollbarsSuppressed(true);
1418 m_firstLayout = false;
1419 m_firstLayoutCallbackPending = true;
1420 m_lastViewportSize = sizeForResizeEvent();
1421 m_lastZoomFactor = root->style().zoom();
1423 // Set the initial vMode to AlwaysOn if we're auto.
1424 if (vMode == ScrollbarAuto)
1425 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1426 // Set the initial hMode to AlwaysOff if we're auto.
1427 if (hMode == ScrollbarAuto)
1428 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1429 Page* page = frame().page();
1430 if (page && page->expectsWheelEventTriggers())
1431 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
1432 setScrollbarModes(hMode, vMode);
1433 setScrollbarsSuppressed(false, true);
1435 setScrollbarModes(hMode, vMode);
1438 LayoutSize oldSize = m_size;
1439 m_size = layoutSize();
1441 if (oldSize != m_size) {
1442 LOG(Layout, " layout size changed from %.3fx%.3f to %.3fx%.3f", oldSize.width().toFloat(), oldSize.height().toFloat(), m_size.width().toFloat(), m_size.height().toFloat());
1443 m_needsFullRepaint = true;
1444 if (!m_firstLayout) {
1445 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : nullptr;
1446 auto* body = document.bodyOrFrameset();
1447 RenderBox* bodyRenderer = rootRenderer && body ? body->renderBox() : nullptr;
1448 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1449 bodyRenderer->setChildNeedsLayout();
1450 else if (rootRenderer && rootRenderer->stretchesToViewport())
1451 rootRenderer->setChildNeedsLayout();
1455 m_layoutPhase = InPreLayout;
1458 layer = root->enclosingLayer();
1459 SubtreeLayoutStateMaintainer subtreeLayoutStateMaintainer(m_layoutRoot);
1461 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1463 ASSERT(m_layoutPhase == InPreLayout);
1464 m_layoutPhase = InRenderTreeLayout;
1466 forceLayoutParentViewIfNeeded();
1468 ASSERT(m_layoutPhase == InRenderTreeLayout);
1470 RenderTreeNeedsLayoutChecker checker(*root);
1473 ASSERT(!root->view().renderTreeIsBeingMutatedInternally());
1475 #if ENABLE(TEXT_AUTOSIZING)
1476 if (frame().settings().textAutosizingEnabled() && !root->view().printing()) {
1477 float minimumZoomFontSize = frame().settings().minimumZoomFontSize();
1478 float textAutosizingWidth = frame().page() ? frame().page()->textAutosizingWidth() : 0;
1479 if (int overrideWidth = frame().settings().textAutosizingWindowSizeOverride().width())
1480 textAutosizingWidth = overrideWidth;
1482 LOG(TextAutosizing, "Text Autosizing: minimumZoomFontSize=%.2f textAutosizingWidth=%.2f", minimumZoomFontSize, textAutosizingWidth);
1484 if (minimumZoomFontSize && textAutosizingWidth) {
1485 root->adjustComputedFontSizesOnBlocks(minimumZoomFontSize, textAutosizingWidth);
1486 if (root->needsLayout())
1492 ASSERT(m_layoutPhase == InRenderTreeLayout);
1493 m_layoutRoot = nullptr;
1494 // Close block here to end the scope of changeSchedulingEnabled and SubtreeLayoutStateMaintainer.
1497 m_layoutPhase = InViewSizeAdjust;
1499 bool neededFullRepaint = m_needsFullRepaint;
1501 if (!subtree && !downcast<RenderView>(*root).printing())
1504 m_layoutPhase = InPostLayout;
1506 m_needsFullRepaint = neededFullRepaint;
1508 // Now update the positions of all layers.
1509 if (m_needsFullRepaint)
1510 root->view().repaintRootContents();
1512 root->view().releaseProtectedRenderWidgets();
1514 ASSERT(!root->needsLayout());
1516 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1518 updateCompositingLayersAfterLayout();
1520 m_layoutPhase = InPostLayerPositionsUpdatedAfterLayout;
1524 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1525 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1526 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1529 #if ENABLE(DASHBOARD_SUPPORT)
1530 updateAnnotatedRegions();
1533 #if ENABLE(IOS_TOUCH_EVENTS)
1534 document.dirtyTouchEventRects();
1537 updateCanBlitOnScrollRecursively();
1539 handleDeferredScrollUpdateAfterContentSizeChange();
1541 handleDeferredScrollbarsUpdateAfterDirectionChange();
1543 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1544 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1546 frame().document()->markers().invalidateRectsForAllMarkers();
1548 if (!m_postLayoutTasksTimer.isActive()) {
1549 if (!m_inSynchronousPostLayout) {
1550 if (inChildFrameLayoutWithFrameFlattening)
1551 updateWidgetPositions();
1553 SetForScope<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1554 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1558 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1559 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1560 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1561 // can make us need to update again, and we can get stuck in a nasty cycle unless
1562 // we call it through the timer here.
1563 m_postLayoutTasksTimer.startOneShot(0);
1569 InspectorInstrumentation::didLayout(cookie, *root);
1570 DebugPageOverlays::didLayout(frame());
1572 --m_nestedLayoutCount;
1575 bool FrameView::shouldDeferScrollUpdateAfterContentSizeChange()
1577 return (m_layoutPhase < InPostLayout) && (m_layoutPhase != OutsideLayout);
1580 RenderBox* FrameView::embeddedContentBox() const
1582 RenderView* renderView = this->renderView();
1586 RenderObject* firstChild = renderView->firstChild();
1588 // Curently only embedded SVG documents participate in the size-negotiation logic.
1589 if (is<RenderSVGRoot>(firstChild))
1590 return downcast<RenderSVGRoot>(firstChild);
1595 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1597 if (!m_embeddedObjectsToUpdate)
1598 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1600 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1601 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
1602 // Tell the DOM element that it needs a widget update.
1603 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
1604 if (!pluginElement.needsCheckForSizeChange())
1605 pluginElement.setNeedsWidgetUpdate(true);
1608 m_embeddedObjectsToUpdate->add(&embeddedObject);
1611 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1613 if (!m_embeddedObjectsToUpdate)
1616 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1619 void FrameView::setMediaType(const String& mediaType)
1621 m_mediaType = mediaType;
1624 String FrameView::mediaType() const
1626 // See if we have an override type.
1627 String overrideType = frame().loader().client().overrideMediaType();
1628 InspectorInstrumentation::applyEmulatedMedia(frame(), overrideType);
1629 if (!overrideType.isNull())
1630 return overrideType;
1634 void FrameView::adjustMediaTypeForPrinting(bool printing)
1637 if (m_mediaTypeWhenNotPrinting.isNull())
1638 m_mediaTypeWhenNotPrinting = mediaType();
1639 setMediaType("print");
1641 if (!m_mediaTypeWhenNotPrinting.isNull())
1642 setMediaType(m_mediaTypeWhenNotPrinting);
1643 m_mediaTypeWhenNotPrinting = String();
1647 bool FrameView::useSlowRepaints(bool considerOverlap) const
1649 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1651 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1652 // m_contentIsOpaque, so don't take the fast path for composited layers
1653 // if they are a platform widget in order to get painting correctness
1654 // for transparent layers. See the comment in WidgetMac::paint.
1655 if (usesCompositedScrolling() && !platformWidget())
1658 bool isOverlapped = m_isOverlapped && considerOverlap;
1660 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1663 if (FrameView* parentView = parentFrameView())
1664 return parentView->useSlowRepaints(considerOverlap);
1669 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1671 return useSlowRepaints(false);
1674 void FrameView::updateCanBlitOnScrollRecursively()
1676 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
1677 if (FrameView* view = frame->view())
1678 view->setCanBlitOnScroll(!view->useSlowRepaints());
1682 bool FrameView::usesCompositedScrolling() const
1684 RenderView* renderView = this->renderView();
1685 if (renderView && renderView->isComposited()) {
1686 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1687 if (layer && layer->drawsContent())
1694 bool FrameView::usesAsyncScrolling() const
1696 #if ENABLE(ASYNC_SCROLLING)
1697 if (Page* page = frame().page()) {
1698 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1699 return scrollingCoordinator->coordinatesScrollingForFrameView(*this);
1705 bool FrameView::usesMockScrollAnimator() const
1707 return Settings::usesMockScrollAnimator();
1710 void FrameView::logMockScrollAnimatorMessage(const String& message) const
1712 Document* document = frame().document();
1715 StringBuilder builder;
1716 if (frame().isMainFrame())
1717 builder.appendLiteral("Main");
1718 builder.appendLiteral("FrameView: ");
1719 builder.append(message);
1720 document->addConsoleMessage(MessageSource::Other, MessageLevel::Debug, builder.toString());
1723 void FrameView::setCannotBlitToWindow()
1725 m_cannotBlitToWindow = true;
1726 updateCanBlitOnScrollRecursively();
1729 void FrameView::addSlowRepaintObject(RenderElement* o)
1731 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1733 if (!m_slowRepaintObjects)
1734 m_slowRepaintObjects = std::make_unique<HashSet<const RenderElement*>>();
1736 m_slowRepaintObjects->add(o);
1738 if (!hadSlowRepaintObjects) {
1739 updateCanBlitOnScrollRecursively();
1741 if (Page* page = frame().page()) {
1742 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1743 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(*this);
1748 void FrameView::removeSlowRepaintObject(RenderElement* o)
1750 if (!m_slowRepaintObjects)
1753 m_slowRepaintObjects->remove(o);
1754 if (m_slowRepaintObjects->isEmpty()) {
1755 m_slowRepaintObjects = nullptr;
1756 updateCanBlitOnScrollRecursively();
1758 if (Page* page = frame().page()) {
1759 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1760 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(*this);
1765 void FrameView::addViewportConstrainedObject(RenderElement* object)
1767 if (!m_viewportConstrainedObjects)
1768 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1770 if (!m_viewportConstrainedObjects->contains(object)) {
1771 m_viewportConstrainedObjects->add(object);
1772 if (platformWidget())
1773 updateCanBlitOnScrollRecursively();
1775 if (Page* page = frame().page()) {
1776 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1777 scrollingCoordinator->frameViewFixedObjectsDidChange(*this);
1782 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1784 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1785 if (Page* page = frame().page()) {
1786 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1787 scrollingCoordinator->frameViewFixedObjectsDidChange(*this);
1790 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1791 // why isn't the same check being made here?
1792 updateCanBlitOnScrollRecursively();
1796 // visualViewport and layoutViewport are both in content coordinates (unzoomed).
1797 LayoutPoint FrameView::computeLayoutViewportOrigin(const LayoutRect& visualViewport, const LayoutPoint& stableLayoutViewportOriginMin, const LayoutPoint& stableLayoutViewportOriginMax, const LayoutRect& layoutViewport)
1799 LayoutPoint layoutViewportOrigin = layoutViewport.location();
1801 if (visualViewport.x() < layoutViewport.x() || visualViewport.x() < stableLayoutViewportOriginMin.x())
1802 layoutViewportOrigin.setX(visualViewport.x());
1804 if (visualViewport.y() < layoutViewport.y() || visualViewport.y() < stableLayoutViewportOriginMin.y())
1805 layoutViewportOrigin.setY(visualViewport.y());
1807 if (visualViewport.maxX() > layoutViewport.maxX() || (visualViewport.maxX() - layoutViewport.width()) > stableLayoutViewportOriginMax.x())
1808 layoutViewportOrigin.setX(visualViewport.maxX() - layoutViewport.width());
1810 if (visualViewport.maxY() > layoutViewport.maxY() || (visualViewport.maxY() - layoutViewport.height()) > stableLayoutViewportOriginMax.y())
1811 layoutViewportOrigin.setY(visualViewport.maxY() - layoutViewport.height());
1813 return layoutViewportOrigin;
1816 void FrameView::setBaseLayoutViewportOrigin(LayoutPoint origin, TriggerLayoutOrNot layoutTriggering)
1818 ASSERT(frame().settings().visualViewportEnabled());
1820 if (origin == m_layoutViewportOrigin)
1823 m_layoutViewportOrigin = origin;
1824 if (layoutTriggering == TriggerLayoutOrNot::Yes)
1825 setViewportConstrainedObjectsNeedLayout();
1827 if (TiledBacking* tiledBacking = this->tiledBacking()) {
1828 FloatRect layoutViewport = layoutViewportRect();
1829 layoutViewport.moveBy(unscaledScrollOrigin()); // tiledBacking deals in top-left relative coordinates.
1830 tiledBacking->setLayoutViewportRect(layoutViewport);
1834 void FrameView::setLayoutViewportOverrideRect(Optional<LayoutRect> rect)
1836 if (rect == m_layoutViewportOverrideRect)
1839 LayoutRect oldRect = layoutViewportRect();
1840 m_layoutViewportOverrideRect = rect;
1842 LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " setLayoutViewportOverrideRect() - changing layout viewport from " << oldRect << " to " << m_layoutViewportOverrideRect.value());
1844 // FIXME: do we need to also do this if the origin changes?
1845 if (oldRect.size() != layoutViewportRect().size())
1846 setViewportConstrainedObjectsNeedLayout();
1849 LayoutSize FrameView::baseLayoutViewportSize() const
1851 return renderView() ? renderView()->size() : size();
1854 void FrameView::updateLayoutViewport()
1856 if (!frame().settings().visualViewportEnabled())
1859 if (m_layoutViewportOverrideRect) {
1860 LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " updateLayoutViewport() - has layoutViewportOverrideRect" << m_layoutViewportOverrideRect.value());
1864 LayoutRect layoutViewport = layoutViewportRect();
1866 LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " updateLayoutViewport()");
1867 LOG_WITH_STREAM(Scrolling, stream << "layoutViewport: " << layoutViewport);
1868 LOG_WITH_STREAM(Scrolling, stream << "visualViewport: " << visualViewportRect());
1869 LOG_WITH_STREAM(Scrolling, stream << "scroll positions: min: " << unscaledMinimumScrollPosition() << " max: "<< unscaledMaximumScrollPosition());
1871 LayoutPoint newLayoutViewportOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport);
1872 if (newLayoutViewportOrigin != m_layoutViewportOrigin) {
1873 setBaseLayoutViewportOrigin(newLayoutViewportOrigin);
1874 LOG_WITH_STREAM(Scrolling, stream << "layoutViewport changed to " << layoutViewportRect());
1878 LayoutPoint FrameView::minStableLayoutViewportOrigin() const
1880 return unscaledMinimumScrollPosition();
1883 LayoutPoint FrameView::maxStableLayoutViewportOrigin() const
1885 return unscaledMaximumScrollPosition();
1888 IntPoint FrameView::unscaledScrollOrigin() const
1890 if (RenderView* renderView = this->renderView())
1891 return -renderView->unscaledDocumentRect().location(); // Akin to code in adjustViewSize().
1896 LayoutRect FrameView::layoutViewportRect() const
1898 if (m_layoutViewportOverrideRect)
1899 return m_layoutViewportOverrideRect.value();
1901 // Size of initial containing block, anchored at scroll position, in document coordinates (unchanged by scale factor).
1902 return LayoutRect(m_layoutViewportOrigin, renderView() ? renderView()->size() : size());
1905 LayoutRect FrameView::visualViewportRect() const
1907 // This isn't visibleContentRect(), because that uses a scaled scroll origin. Confused? Me too.
1908 FloatRect visibleContentRect = this->visibleContentRect(LegacyIOSDocumentVisibleRect);
1909 visibleContentRect.scale(1 / frameScaleFactor()); // Note that frameScaleFactor() returns 1 for delegated scrolling (e.g. iOS WK2)
1910 return LayoutRect(visibleContentRect);
1913 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1915 ASSERT(!frame().settings().visualViewportEnabled());
1918 if (useCustomFixedPositionLayoutRect())
1919 return customFixedPositionLayoutRect();
1921 LayoutRect viewportRect = visibleContentRect();
1923 viewportRect.setLocation(scrollPositionForFixedPosition());
1924 return viewportRect;
1927 LayoutRect FrameView::rectForFixedPositionLayout() const
1929 if (frame().settings().visualViewportEnabled())
1930 return layoutViewportRect();
1932 return viewportConstrainedVisibleContentRect();
1935 float FrameView::frameScaleFactor() const
1937 return frame().frameScaleFactor();
1940 LayoutPoint FrameView::scrollPositionForFixedPosition() const
1942 if (frame().settings().visualViewportEnabled())
1943 return layoutViewportRect().location();
1945 return scrollPositionForFixedPosition(visibleContentRect(), totalContentsSize(), scrollPosition(), scrollOrigin(), frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements(), headerHeight(), footerHeight());
1948 LayoutPoint FrameView::scrollPositionForFixedPosition(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements behaviorForFixed, int headerHeight, int footerHeight)
1950 LayoutPoint position;
1951 if (behaviorForFixed == StickToDocumentBounds)
1952 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1954 position = scrollPosition;
1955 position.setY(position.y() - headerHeight);
1958 LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
1960 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1961 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1963 return LayoutPoint(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1966 float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset)
1968 if (!topContentInset)
1971 // The insetClipLayer should not move for negative scroll values.
1972 float scrollY = std::max<float>(0, scrollPosition.y());
1974 if (scrollY >= topContentInset)
1977 return topContentInset - scrollY;
1980 float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset)
1982 if (!topContentInset)
1985 float scrollY = std::max<float>(0, scrollPosition.y());
1987 if (scrollY >= topContentInset)
1988 return topContentInset;
1993 float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight)
1995 return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight;
1998 FloatPoint FrameView::positionForRootContentLayer(const FloatPoint& scrollPosition, const FloatPoint& scrollOrigin, float topContentInset, float headerHeight)
2000 return FloatPoint(0, yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight) - toFloatSize(scrollOrigin);
2003 FloatPoint FrameView::positionForRootContentLayer() const
2005 return positionForRootContentLayer(scrollPosition(), scrollOrigin(), topContentInset(), headerHeight());
2009 LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
2011 if (fixedElementsLayoutRelativeToFrame)
2012 return visibleContentRect;
2014 if (totalContentsSize.isEmpty())
2015 return visibleContentRect;
2017 // We impose an lower limit on the size (so an upper limit on the scale) of
2018 // the rect used to position fixed objects so that they don't crowd into the
2019 // center of the screen at larger scales.
2020 const LayoutUnit maxContentWidthForZoomThreshold = LayoutUnit::fromPixel(1024);
2021 float zoomedOutScale = frameScaleFactor * visibleContentRect.width() / std::min(maxContentWidthForZoomThreshold, totalContentsSize.width());
2022 float constraintThresholdScale = 1.5 * zoomedOutScale;
2023 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
2025 LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
2027 if (frameScaleFactor > constraintThresholdScale) {
2028 FloatRect contentRect(FloatPoint(), totalContentsSize);
2029 FloatRect viewportRect = visibleContentRect;
2031 // Scale the rect up from a point that is relative to its position in the viewport.
2032 FloatSize sizeDelta = contentRect.size() - viewportRect.size();
2034 FloatPoint scaleOrigin;
2035 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
2036 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
2038 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
2039 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
2040 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
2042 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
2045 if (scrollBehavior == StickToDocumentBounds) {
2046 LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
2047 viewportConstrainedObjectsRect.intersect(documentBounds);
2050 return viewportConstrainedObjectsRect;
2053 LayoutRect FrameView::viewportConstrainedObjectsRect() const
2055 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
2059 ScrollPosition FrameView::minimumScrollPosition() const
2061 ScrollPosition minimumPosition = ScrollView::minimumScrollPosition();
2063 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
2064 minimumPosition.setY(maximumScrollPosition().y());
2066 return minimumPosition;
2069 ScrollPosition FrameView::maximumScrollPosition() const
2071 ScrollPosition maximumPosition = ScrollView::maximumScrollPosition();
2073 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
2074 maximumPosition.setY(minimumScrollPosition().y());
2076 return maximumPosition;
2079 ScrollPosition FrameView::unscaledMinimumScrollPosition() const
2081 if (RenderView* renderView = this->renderView()) {
2082 IntRect unscaledDocumentRect = renderView->unscaledDocumentRect();
2083 ScrollPosition minimumPosition = unscaledDocumentRect.location();
2085 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
2086 minimumPosition.setY(unscaledMaximumScrollPosition().y());
2088 return minimumPosition;
2091 return minimumScrollPosition();
2094 ScrollPosition FrameView::unscaledMaximumScrollPosition() const
2096 if (RenderView* renderView = this->renderView()) {
2097 IntRect unscaledDocumentRect = renderView->unscaledDocumentRect();
2098 unscaledDocumentRect.expand(0, headerHeight() + footerHeight());
2099 ScrollPosition maximumPosition = ScrollPosition(unscaledDocumentRect.maxXMaxYCorner() - visibleSize()).expandedTo({ 0, 0 });
2101 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
2102 maximumPosition.setY(unscaledMinimumScrollPosition().y());
2104 return maximumPosition;
2107 return maximumScrollPosition();
2110 void FrameView::viewportContentsChanged()
2112 if (!frame().view()) {
2113 // The frame is being destroyed.
2117 // When the viewport contents changes (scroll, resize, style recalc, layout, ...),
2118 // check if we should resume animated images or unthrottle DOM timers.
2119 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) {
2120 frameView.resumeVisibleImageAnimations(visibleRect);
2121 frameView.updateScriptedAnimationsAndTimersThrottlingState(visibleRect);
2123 if (auto* renderView = frameView.frame().contentRenderer())
2124 renderView->updateVisibleViewportRect(visibleRect);
2128 bool FrameView::fixedElementsLayoutRelativeToFrame() const
2130 return frame().settings().fixedElementsLayoutRelativeToFrame();
2133 IntPoint FrameView::lastKnownMousePosition() const
2135 return frame().eventHandler().lastKnownMousePosition();
2138 bool FrameView::isHandlingWheelEvent() const
2140 return frame().eventHandler().isHandlingWheelEvent();
2143 bool FrameView::shouldSetCursor() const
2145 Page* page = frame().page();
2146 return page && page->isVisible() && page->focusController().isActive();
2149 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
2151 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
2152 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
2156 const bool isCompositedContentLayer = usesCompositedScrolling();
2158 // Get the rects of the fixed objects visible in the rectToScroll
2159 Region regionToUpdate;
2160 for (auto& renderer : *m_viewportConstrainedObjects) {
2161 if (!renderer->style().hasViewportConstrainedPosition())
2163 if (renderer->isComposited())
2166 // Fixed items should always have layers.
2167 ASSERT(renderer->hasLayer());
2168 RenderLayer* layer = downcast<RenderBoxModelObject>(*renderer).layer();
2170 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
2171 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
2172 // Don't invalidate for invisible fixed layers.
2176 if (layer->hasAncestorWithFilterOutsets()) {
2177 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
2178 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
2182 // FIXME: use pixel snapping instead of enclosing when ScrollView has finished transitioning from IntRect to Float/LayoutRect.
2183 IntRect updateRect = enclosingIntRect(layer->repaintRectIncludingNonCompositingDescendants());
2184 updateRect = contentsToRootView(updateRect);
2185 if (!isCompositedContentLayer && clipsRepaints())
2186 updateRect.intersect(rectToScroll);
2187 if (!updateRect.isEmpty())
2188 regionToUpdate.unite(updateRect);
2192 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
2194 // 2) update the area of fixed objects that has been invalidated
2195 for (auto& updateRect : regionToUpdate.rects()) {
2196 IntRect scrolledRect = updateRect;
2197 scrolledRect.move(scrollDelta);
2198 updateRect.unite(scrolledRect);
2199 if (isCompositedContentLayer) {
2200 updateRect = rootViewToContents(updateRect);
2201 ASSERT(renderView());
2202 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
2205 if (clipsRepaints())
2206 updateRect.intersect(rectToScroll);
2207 hostWindow()->invalidateContentsAndRootView(updateRect);
2213 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
2215 repaintSlowRepaintObjects();
2217 if (!usesCompositedScrolling() && isEnclosedInCompositingLayer()) {
2218 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
2219 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), frameRenderer->borderTop() + frameRenderer->paddingTop(),
2220 visibleWidth(), visibleHeight());
2221 frameRenderer->repaintRectangle(rect);
2226 ScrollView::scrollContentsSlowPath(updateRect);
2229 void FrameView::repaintSlowRepaintObjects()
2231 if (!m_slowRepaintObjects)
2234 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
2235 // repaint them after scrolling.
2236 for (auto& renderer : *m_slowRepaintObjects)
2237 renderer->repaintSlowRepaintObject();
2240 // Note that this gets called at painting time.
2241 void FrameView::setIsOverlapped(bool isOverlapped)
2243 if (isOverlapped == m_isOverlapped)
2246 m_isOverlapped = isOverlapped;
2247 updateCanBlitOnScrollRecursively();
2250 void FrameView::setContentIsOpaque(bool contentIsOpaque)
2252 if (contentIsOpaque == m_contentIsOpaque)
2255 m_contentIsOpaque = contentIsOpaque;
2256 updateCanBlitOnScrollRecursively();
2259 void FrameView::restoreScrollbar()
2261 setScrollbarsSuppressed(false);
2264 bool FrameView::scrollToFragment(const URL& url)
2266 // If our URL has no ref, then we have no place we need to jump to.
2267 // OTOH If CSS target was set previously, we want to set it to 0, recalc
2268 // and possibly repaint because :target pseudo class may have been
2269 // set (see bug 11321).
2270 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
2273 String fragmentIdentifier = url.fragmentIdentifier();
2274 if (scrollToAnchor(fragmentIdentifier))
2277 // Try again after decoding the ref, based on the document's encoding.
2278 if (TextResourceDecoder* decoder = frame().document()->decoder())
2279 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
2284 bool FrameView::scrollToAnchor(const String& name)
2286 ASSERT(frame().document());
2287 auto& document = *frame().document();
2289 if (!document.haveStylesheetsLoaded()) {
2290 document.setGotoAnchorNeededAfterStylesheetsLoad(true);
2294 document.setGotoAnchorNeededAfterStylesheetsLoad(false);
2296 Element* anchorElement = document.findAnchor(name);
2298 // Setting to null will clear the current target.
2299 document.setCSSTarget(anchorElement);
2301 if (is<SVGDocument>(document)) {
2302 if (auto* rootElement = SVGDocument::rootElement(document)) {
2303 rootElement->scrollToAnchor(name, anchorElement);
2309 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2310 if (!anchorElement && !(name.isEmpty() || equalLettersIgnoringASCIICase(name, "top")))
2313 ContainerNode* scrollPositionAnchor = anchorElement;
2314 if (!scrollPositionAnchor)
2315 scrollPositionAnchor = frame().document();
2316 maintainScrollPositionAtAnchor(scrollPositionAnchor);
2318 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
2319 if (anchorElement) {
2320 if (anchorElement->isFocusable())
2321 document.setFocusedElement(anchorElement);
2323 document.setFocusedElement(nullptr);
2324 document.setFocusNavigationStartingNode(anchorElement);
2331 void FrameView::maintainScrollPositionAtAnchor(ContainerNode* anchorNode)
2333 m_maintainScrollPositionAnchor = anchorNode;
2334 if (!m_maintainScrollPositionAnchor)
2337 // We need to update the layout before scrolling, otherwise we could
2338 // really mess things up if an anchor scroll comes at a bad moment.
2339 frame().document()->updateStyleIfNeeded();
2340 // Only do a layout if changes have occurred that make it necessary.
2341 RenderView* renderView = this->renderView();
2342 if (renderView && renderView->needsLayout())
2348 void FrameView::scrollElementToRect(const Element& element, const IntRect& rect)
2350 frame().document()->updateLayoutIgnorePendingStylesheets();
2353 if (RenderElement* renderer = element.renderer())
2354 bounds = renderer->anchorRect();
2355 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
2356 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
2357 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
2360 void FrameView::setScrollPosition(const ScrollPosition& scrollPosition)
2362 SetForScope<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
2363 m_maintainScrollPositionAnchor = nullptr;
2364 Page* page = frame().page();
2365 if (page && page->expectsWheelEventTriggers())
2366 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
2367 ScrollView::setScrollPosition(scrollPosition);
2370 void FrameView::contentsResized()
2372 // For non-delegated scrolling, adjustTiledBackingScrollability() is called via addedOrRemovedScrollbar() which occurs less often.
2373 if (delegatesScrolling())
2374 adjustTiledBackingScrollability();
2377 void FrameView::delegatesScrollingDidChange()
2379 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
2380 if (hasCompositedContent())
2381 clearBackingStores();
2384 #if USE(COORDINATED_GRAPHICS)
2385 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
2387 bool visibleContentSizeDidChange = false;
2388 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
2389 // When the viewport size changes or the content is scaled, we need to
2390 // reposition the fixed and sticky positioned elements.
2391 setViewportConstrainedObjectsNeedLayout();
2392 visibleContentSizeDidChange = true;
2395 IntPoint oldPosition = scrollPosition();
2396 ScrollView::setFixedVisibleContentRect(visibleContentRect);
2397 IntPoint newPosition = scrollPosition();
2398 if (oldPosition != newPosition) {
2399 updateLayerPositionsAfterScrolling();
2400 if (frame().settings().acceleratedCompositingForFixedPositionEnabled())
2401 updateCompositingLayersAfterScrolling();
2402 scrollAnimator().setCurrentPosition(newPosition);
2403 scrollPositionChanged(oldPosition, newPosition);
2405 if (visibleContentSizeDidChange) {
2406 // Update the scroll-bars to calculate new page-step size.
2407 updateScrollbars(scrollPosition());
2409 didChangeScrollOffset();
2413 void FrameView::setViewportConstrainedObjectsNeedLayout()
2415 if (!hasViewportConstrainedObjects())
2418 for (auto& renderer : *m_viewportConstrainedObjects)
2419 renderer->setNeedsLayout();
2422 void FrameView::didChangeScrollOffset()
2424 frame().mainFrame().pageOverlayController().didScrollFrame(frame());
2425 frame().loader().client().didChangeScrollOffset();
2428 void FrameView::scrollOffsetChangedViaPlatformWidgetImpl(const ScrollOffset& oldOffset, const ScrollOffset& newOffset)
2430 updateLayerPositionsAfterScrolling();
2431 updateCompositingLayersAfterScrolling();
2432 repaintSlowRepaintObjects();
2433 scrollPositionChanged(scrollPositionFromOffset(oldOffset), scrollPositionFromOffset(newOffset));
2436 // These scroll positions are affected by zooming.
2437 void FrameView::scrollPositionChanged(const ScrollPosition& oldPosition, const ScrollPosition& newPosition)
2439 Page* page = frame().page();
2440 Seconds throttlingDelay = page ? page->chrome().client().eventThrottlingDelay() : Seconds(0);
2442 if (throttlingDelay == Seconds(0)) {
2443 m_delayedScrollEventTimer.stop();
2445 } else if (!m_delayedScrollEventTimer.isActive())
2446 m_delayedScrollEventTimer.startOneShot(throttlingDelay.value());
2448 if (Document* document = frame().document())
2449 document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize());
2451 if (RenderView* renderView = this->renderView()) {
2452 if (renderView->usesCompositing())
2453 renderView->compositor().frameViewDidScroll();
2456 LOG_WITH_STREAM(Scrolling, stream << "FrameView " << this << " scrollPositionChanged from " << oldPosition << " to " << newPosition << " (scale " << frameScaleFactor() << " )");
2457 updateLayoutViewport();
2458 viewportContentsChanged();
2461 void FrameView::applyRecursivelyWithVisibleRect(const std::function<void (FrameView& frameView, const IntRect& visibleRect)>& apply)
2463 IntRect windowClipRect = this->windowClipRect();
2464 auto visibleRect = windowToContents(windowClipRect);
2465 apply(*this, visibleRect);
2467 // Recursive call for subframes. We cache the current FrameView's windowClipRect to avoid recomputing it for every subframe.
2468 SetForScope<IntRect*> windowClipRectCache(m_cachedWindowClipRect, &windowClipRect);
2469 for (Frame* childFrame = frame().tree().firstChild(); childFrame; childFrame = childFrame->tree().nextSibling()) {
2470 if (auto* childView = childFrame->view())
2471 childView->applyRecursivelyWithVisibleRect(apply);
2475 void FrameView::resumeVisibleImageAnimations(const IntRect& visibleRect)
2477 if (visibleRect.isEmpty())
2480 if (auto* renderView = frame().contentRenderer())
2481 renderView->resumePausedImageAnimationsIfNeeded(visibleRect);
2484 void FrameView::updateScriptedAnimationsAndTimersThrottlingState(const IntRect& visibleRect)
2486 if (frame().isMainFrame())
2489 auto* document = frame().document();
2493 // We don't throttle zero-size or display:none frames because those are usually utility frames.
2494 bool shouldThrottle = visibleRect.isEmpty() && !m_size.isEmpty() && frame().ownerRenderer();
2496 #if ENABLE(REQUEST_ANIMATION_FRAME)
2497 if (auto* scriptedAnimationController = document->scriptedAnimationController())
2498 scriptedAnimationController->setThrottled(shouldThrottle);
2501 document->setTimerThrottlingEnabled(shouldThrottle);
2505 void FrameView::resumeVisibleImageAnimationsIncludingSubframes()
2507 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) {
2508 frameView.resumeVisibleImageAnimations(visibleRect);
2512 void FrameView::updateLayerPositionsAfterScrolling()
2514 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2515 if (m_layoutPhase == InViewSizeAdjust)
2518 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2519 if (RenderView* renderView = this->renderView()) {
2520 updateWidgetPositions();
2521 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2526 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2528 #if ENABLE(ASYNC_SCROLLING)
2529 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2531 Page* page = frame().page();
2535 if (&page->mainFrame() != m_frame.ptr())
2538 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2539 if (!scrollingCoordinator)
2542 if (!scrollingCoordinator->supportsFixedPositionLayers())
2545 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this))
2548 if (inProgrammaticScroll())
2556 void FrameView::updateCompositingLayersAfterScrolling()
2558 ASSERT(m_layoutPhase >= InPostLayout || m_layoutPhase == OutsideLayout);
2560 if (!shouldUpdateCompositingLayersAfterScrolling())
2563 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2564 if (RenderView* renderView = this->renderView())
2565 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2569 bool FrameView::isRubberBandInProgress() const
2571 if (scrollbarsSuppressed())
2574 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2575 // ScrollingCoordinator::isRubberBandInProgress().
2576 if (Page* page = frame().page()) {
2577 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2578 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this))
2579 return scrollingCoordinator->isRubberBandInProgress();
2583 // If the main thread updates the scroll position for this FrameView, we should return
2584 // ScrollAnimator::isRubberBandInProgress().
2585 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2586 return scrollAnimator->isRubberBandInProgress();
2591 bool FrameView::requestScrollPositionUpdate(const ScrollPosition& position)
2593 LOG_WITH_STREAM(Scrolling, stream << "FrameView::requestScrollPositionUpdate " << position);
2595 #if ENABLE(ASYNC_SCROLLING)
2596 if (TiledBacking* tiledBacking = this->tiledBacking())
2597 tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size()));
2600 #if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
2601 if (Page* page = frame().page()) {
2602 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2603 return scrollingCoordinator->requestScrollPositionUpdate(*this, position);
2606 UNUSED_PARAM(position);
2612 HostWindow* FrameView::hostWindow() const
2614 if (Page* page = frame().page())
2615 return &page->chrome();
2619 void FrameView::addTrackedRepaintRect(const FloatRect& r)
2621 if (!m_isTrackingRepaints || r.isEmpty())
2624 FloatRect repaintRect = r;
2625 repaintRect.moveBy(-scrollPosition());
2626 m_trackedRepaintRects.append(repaintRect);
2629 void FrameView::repaintContentRectangle(const IntRect& r)
2631 ASSERT(!frame().ownerElement());
2633 if (!shouldUpdate())
2636 ScrollView::repaintContentRectangle(r);
2639 static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderElement& renderer, unsigned threshold)
2642 for (const RenderObject* descendant = &renderer; descendant; descendant = descendant->nextInPreOrder()) {
2643 if (is<RenderText>(*descendant)) {
2644 count += downcast<RenderText>(*descendant).text()->length();
2645 if (count >= threshold)
2652 bool FrameView::renderedCharactersExceed(unsigned threshold)
2654 if (!frame().contentRenderer())
2656 return countRenderedCharactersInRenderObjectWithThreshold(*frame().contentRenderer(), threshold) >= threshold;
2659 void FrameView::availableContentSizeChanged(AvailableSizeChangeReason reason)
2661 if (Document* document = frame().document())
2662 document->updateViewportUnitsOnResize();
2664 updateLayoutViewport();
2666 ScrollView::availableContentSizeChanged(reason);
2669 bool FrameView::shouldLayoutAfterContentsResized() const
2671 return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2674 void FrameView::updateContentsSize()
2676 // We check to make sure the view is attached to a frame() as this method can
2677 // be triggered before the view is attached by Frame::createView(...) setting
2678 // various values such as setScrollBarModes(...) for example. An ASSERT is
2679 // triggered when a view is layout before being attached to a frame().
2680 if (!frame().view())
2684 if (RenderView* root = m_frame->contentRenderer()) {
2685 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2686 setViewportConstrainedObjectsNeedLayout();
2687 // We must eagerly enter compositing mode because fixed position elements
2688 // will not have been made compositing via a preceding style change before
2689 // m_useCustomFixedPositionLayoutRect was true.
2690 root->compositor().enableCompositingMode();
2695 if (shouldLayoutAfterContentsResized() && needsLayout())
2698 if (RenderView* renderView = this->renderView()) {
2699 if (renderView->usesCompositing())
2700 renderView->compositor().frameViewDidChangeSize();
2704 void FrameView::addedOrRemovedScrollbar()
2706 if (RenderView* renderView = this->renderView()) {
2707 if (renderView->usesCompositing())
2708 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2711 adjustTiledBackingScrollability();
2714 void FrameView::adjustTiledBackingScrollability()
2716 auto* tiledBacking = this->tiledBacking();
2720 bool horizontallyScrollable;
2721 bool verticallyScrollable;
2722 bool clippedByAncestorView = static_cast<bool>(m_viewExposedRect);
2725 if (Page* page = frame().page())
2726 clippedByAncestorView |= page->enclosedInScrollableAncestorView();
2729 if (delegatesScrolling()) {
2730 IntSize documentSize = contentsSize();
2731 IntSize visibleSize = this->visibleSize();
2733 horizontallyScrollable = clippedByAncestorView || documentSize.width() > visibleSize.width();
2734 verticallyScrollable = clippedByAncestorView || documentSize.height() > visibleSize.height();
2736 horizontallyScrollable = clippedByAncestorView || horizontalScrollbar();
2737 verticallyScrollable = clippedByAncestorView || verticalScrollbar();
2740 TiledBacking::Scrollability scrollability = TiledBacking::NotScrollable;
2741 if (horizontallyScrollable)
2742 scrollability = TiledBacking::HorizontallyScrollable;
2744 if (verticallyScrollable)
2745 scrollability |= TiledBacking::VerticallyScrollable;
2747 tiledBacking->setScrollability(scrollability);
2751 void FrameView::unobscuredContentSizeChanged()
2753 adjustTiledBackingScrollability();
2757 static LayerFlushThrottleState::Flags determineLayerFlushThrottleState(Page& page)
2759 // We only throttle when constantly receiving new data during the inital page load.
2760 if (!page.progress().isMainLoadProgressing())
2762 // Scrolling during page loading disables throttling.
2763 if (page.mainFrame().view()->wasScrolledByUser())
2765 // Disable for image documents so large GIF animations don't get throttled during loading.
2766 auto* document = page.mainFrame().document();
2767 if (!document || is<ImageDocument>(*document))
2769 return LayerFlushThrottleState::Enabled;
2772 void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2774 if (!frame().page())
2776 auto& page = *frame().page();
2778 LayerFlushThrottleState::Flags flags = LayerFlushThrottleState::UserIsInteracting | determineLayerFlushThrottleState(page);
2779 if (page.chrome().client().adjustLayerFlushThrottling(flags))
2782 if (RenderView* view = renderView())
2783 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2786 void FrameView::loadProgressingStatusChanged()
2788 updateLayerFlushThrottling();
2789 adjustTiledBackingCoverage();
2792 void FrameView::updateLayerFlushThrottling()
2794 Page* page = frame().page();
2798 ASSERT(frame().isMainFrame());
2800 LayerFlushThrottleState::Flags flags = determineLayerFlushThrottleState(*page);
2802 // See if the client is handling throttling.
2803 if (page->chrome().client().adjustLayerFlushThrottling(flags))
2806 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
2807 if (RenderView* renderView = frame->contentRenderer())
2808 renderView->compositor().setLayerFlushThrottlingEnabled(flags & LayerFlushThrottleState::Enabled);
2812 void FrameView::adjustTiledBackingCoverage()
2814 if (!m_speculativeTilingEnabled)
2815 enableSpeculativeTilingIfNeeded();
2817 RenderView* renderView = this->renderView();
2818 if (renderView && renderView->layer()->backing())
2819 renderView->layer()->backing()->adjustTiledBackingCoverage();
2821 if (LegacyTileCache* tileCache = legacyTileCache())
2822 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2826 static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2828 Page* page = view.frame().page();
2829 return page && view.isVisuallyNonEmpty() && !page->progress().isMainLoadProgressing();
2832 void FrameView::enableSpeculativeTilingIfNeeded()
2834 ASSERT(!m_speculativeTilingEnabled);
2835 if (m_wasScrolledByUser) {
2836 m_speculativeTilingEnabled = true;
2839 if (!shouldEnableSpeculativeTilingDuringLoading(*this))
2841 if (m_speculativeTilingEnableTimer.isActive())
2843 // Delay enabling a bit as load completion may trigger further loading from scripts.
2844 static const double speculativeTilingEnableDelay = 0.5;
2845 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
2848 void FrameView::speculativeTilingEnableTimerFired()
2850 if (m_speculativeTilingEnabled)
2852 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
2853 adjustTiledBackingCoverage();
2856 void FrameView::show()
2860 if (frame().isMainFrame()) {
2861 // Turn off speculative tiling for a brief moment after a FrameView appears on screen.
2862 // Note that adjustTiledBackingCoverage() kicks the (500ms) timer to re-enable it.
2863 m_speculativeTilingEnabled = false;
2864 m_wasScrolledByUser = false;
2865 adjustTiledBackingCoverage();
2868 void FrameView::convertSubtreeLayoutToFullLayout()
2870 ASSERT(m_layoutRoot);
2871 m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No);
2872 m_layoutRoot = nullptr;
2875 void FrameView::layoutTimerFired()
2877 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2878 if (!frame().document()->ownerElement())
2879 printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count());
2884 void FrameView::scheduleRelayout()
2886 // FIXME: We should assert the page is not in the page cache, but that is causing
2887 // too many false assertions. See <rdar://problem/7218118>.
2888 ASSERT(frame().view() == this);
2891 convertSubtreeLayoutToFullLayout();
2892 if (!m_layoutSchedulingEnabled)
2896 if (!frame().document()->shouldScheduleLayout())
2898 InspectorInstrumentation::didInvalidateLayout(frame());
2899 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2900 // Also invalidate parent frame starting from the owner element of this frame.
2901 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2902 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2904 std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay();
2905 if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count())
2906 unscheduleRelayout();
2907 if (m_layoutTimer.isActive())
2910 m_delayedLayout = delay.count();
2912 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2913 if (!frame().document()->ownerElement())
2914 printf("Scheduling layout for %d\n", delay);
2917 m_layoutTimer.startOneShot(delay);
2920 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2922 for (RenderObject* r = descendant; r; r = r->container()) {
2929 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2931 ASSERT(renderView());
2932 const RenderView& renderView = *this->renderView();
2934 // Try to catch unnecessary work during render tree teardown.
2935 ASSERT(!renderView.documentBeingDestroyed());
2936 ASSERT(frame().view() == this);
2938 // When m_layoutRoot is already set, ignore the renderView's needsLayout bit
2939 // since we need to resolve the conflict between the m_layoutRoot and newRelayoutRoot layouts.
2940 if (renderView.needsLayout() && !m_layoutRoot) {
2941 m_layoutRoot = &newRelayoutRoot;
2942 convertSubtreeLayoutToFullLayout();
2946 if (!layoutPending() && m_layoutSchedulingEnabled) {
2947 std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay();
2948 ASSERT(!newRelayoutRoot.container() || is<RenderView>(newRelayoutRoot.container()) || !newRelayoutRoot.container()->needsLayout());
2949 m_layoutRoot = &newRelayoutRoot;
2950 InspectorInstrumentation::didInvalidateLayout(frame());
2951 m_delayedLayout = delay.count();
2952 m_layoutTimer.startOneShot(delay);
2956 if (m_layoutRoot == &newRelayoutRoot)
2959 if (!m_layoutRoot) {
2960 // We already have a pending (full) layout. Just mark the subtree for layout.
2961 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
2962 InspectorInstrumentation::didInvalidateLayout(frame());
2966 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2967 // Keep the current root.
2968 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No, m_layoutRoot);
2969 ASSERT(!m_layoutRoot->container() || is<RenderView>(m_layoutRoot->container()) || !m_layoutRoot->container()->needsLayout());
2973 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2974 // Re-root at newRelayoutRoot.
2975 m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No, &newRelayoutRoot);
2976 m_layoutRoot = &newRelayoutRoot;
2977 ASSERT(!m_layoutRoot->container() || is<RenderView>(m_layoutRoot->container()) || !m_layoutRoot->container()->needsLayout());
2978 InspectorInstrumentation::didInvalidateLayout(frame());
2981 // Two disjoint subtrees need layout. Mark both of them and issue a full layout instead.
2982 convertSubtreeLayoutToFullLayout();
2983 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
2984 InspectorInstrumentation::didInvalidateLayout(frame());
2987 bool FrameView::layoutPending() const
2989 return m_layoutTimer.isActive();
2992 bool FrameView::needsStyleRecalcOrLayout(bool includeSubframes) const
2994 if (frame().document() && frame().document()->childNeedsStyleRecalc())
3000 if (!includeSubframes)
3003 for (auto& frameView : renderedChildFrameViews()) {
3004 if (frameView->needsStyleRecalcOrLayout())
3011 bool FrameView::needsLayout() const
3013 // This can return true in cases where the document does not have a body yet.
3014 // Document::shouldScheduleLayout takes care of preventing us from scheduling
3015 // layout in that case.
3016 RenderView* renderView = this->renderView();
3017 return layoutPending()
3018 || (renderView && renderView->needsLayout())
3020 || (m_deferSetNeedsLayoutCount && m_setNeedsLayoutWasDeferred);
3023 void FrameView::setNeedsLayout()
3025 if (m_deferSetNeedsLayoutCount) {
3026 m_setNeedsLayoutWasDeferred = true;
3030 if (auto* renderView = this->renderView()) {
3031 ASSERT(!renderView->inHitTesting());
3032 renderView->setNeedsLayout();
3036 void FrameView::unscheduleRelayout()
3038 if (m_postLayoutTasksTimer.isActive())
3039 m_postLayoutTasksTimer.stop();
3041 if (!m_layoutTimer.isActive())
3044 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
3045 if (!frame().document()->ownerElement())
3046 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
3049 m_layoutTimer.stop();
3050 m_delayedLayout = false;
3053 #if ENABLE(REQUEST_ANIMATION_FRAME)
3054 void FrameView::serviceScriptedAnimations()
3056 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext()) {
3057 frame->view()->serviceScrollAnimations();
3058 frame->animation().serviceAnimations();
3061 if (!frame().document() || !frame().document()->domWindow())
3064 Vector<RefPtr<Document>> documents;
3065 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext())
3066 documents.append(frame->document());
3068 double timestamp = frame().document()->domWindow()->nowTimestamp();
3069 for (auto& document : documents)
3070 document->serviceScriptedAnimations(timestamp);
3074 bool FrameView::isTransparent() const
3076 return m_isTransparent;
3079 void FrameView::setTransparent(bool isTransparent)
3081 if (m_isTransparent == isTransparent)
3084 m_isTransparent = isTransparent;
3086 // setTransparent can be called in the window between FrameView initialization
3087 // and switching in the new Document; this means that the RenderView that we
3088 // retrieve is actually attached to the previous Document, which is going away,
3089 // and must not update compositing layers.
3090 if (!isViewForDocumentInFrame())
3093 renderView()->compositor().rootBackgroundTransparencyChanged();
3096 bool FrameView::hasOpaqueBackground() const
3098 return !m_isTransparent && m_baseBackgroundColor.isOpaque();
3101 Color FrameView::baseBackgroundColor() const
3103 return m_baseBackgroundColor;
3106 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
3108 bool wasOpaque = m_baseBackgroundColor.isOpaque();
3110 if (!backgroundColor.isValid())
3111 m_baseBackgroundColor = Color::white;
3113 m_baseBackgroundColor = backgroundColor;
3115 if (!isViewForDocumentInFrame())
3118 recalculateScrollbarOverlayStyle();
3120 if (m_baseBackgroundColor.isOpaque() != wasOpaque)
3121 renderView()->compositor().rootBackgroundTransparencyChanged();
3124 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
3126 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
3127 if (FrameView* view = frame->view()) {
3128 view->setTransparent(transparent);
3129 view->setBaseBackgroundColor(backgroundColor);
3134 bool FrameView::hasExtendedBackgroundRectForPainting() const
3136 if (!frame().settings().backgroundShouldExtendBeyondPage())
3139 TiledBacking* tiledBacking = this->tiledBacking();
3143 return tiledBacking->hasMargins();
3146 void FrameView::updateExtendBackgroundIfNecessary()
3148 ExtendedBackgroundMode mode = calculateExtendedBackgroundMode();
3149 if (mode == ExtendedBackgroundModeNone)
3152 updateTilesForExtendedBackgroundMode(mode);
3155 FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
3157 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
3158 // that the background rect needs to be extended for painting. Simple backgrounds can be extended
3159 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
3160 // such as images, require extending the background rect to continue painting into the extended
3161 // region. This function finds out if it is necessary to extend the background rect for painting.
3164 // <rdar://problem/16201373>
3165 return ExtendedBackgroundModeNone;
3167 if (!frame().settings().backgroundShouldExtendBeyondPage())
3168 return ExtendedBackgroundModeNone;
3170 if (!frame().isMainFrame())
3171 return ExtendedBackgroundModeNone;
3173 Document* document = frame().document();
3175 return ExtendedBackgroundModeNone;
3177 auto* documentElement = document->documentElement();
3178 auto* documentElementRenderer = documentElement ? documentElement->renderer() : nullptr;
3179 if (!documentElementRenderer)
3180 return ExtendedBackgroundModeNone;
3182 auto& renderer = documentElementRenderer->rendererForRootBackground();
3183 if (!renderer.style().hasBackgroundImage())
3184 return ExtendedBackgroundModeNone;
3186 ExtendedBackgroundMode mode = ExtendedBackgroundModeNone;
3188 if (renderer.style().backgroundRepeatX() == RepeatFill)
3189 mode |= ExtendedBackgroundModeHorizontal;
3190 if (renderer.style().backgroundRepeatY() == RepeatFill)
3191 mode |= ExtendedBackgroundModeVertical;
3197 void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
3199 if (!frame().settings().backgroundShouldExtendBeyondPage())
3202 RenderView* renderView = this->renderView();
3206 RenderLayerBacking* backing = renderView->layer()->backing();
3210 TiledBacking* tiledBacking = backing->graphicsLayer()->tiledBacking();
3214 ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone;
3215 if (tiledBacking->hasVerticalMargins())
3216 existingMode |= ExtendedBackgroundModeVertical;
3217 if (tiledBacking->hasHorizontalMargins())
3218 existingMode |= ExtendedBackgroundModeHorizontal;
3220 if (existingMode == mode)
3223 renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor());
3224 backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical);
3227 IntRect FrameView::extendedBackgroundRectForPainting() const
3229 TiledBacking* tiledBacking = this->tiledBacking();
3233 RenderView* renderView = this->renderView();
3237 LayoutRect extendedRect = renderView->unextendedBackgroundRect();
3238 if (!tiledBacking->hasMargins())
3239 return snappedIntRect(extendedRect);
3241 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
3242 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
3243 return snappedIntRect(extendedRect);
3246 bool FrameView::shouldUpdateWhileOffscreen() const
3248 return m_shouldUpdateWhileOffscreen;
3251 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
3253 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
3256 bool FrameView::shouldUpdate() const
3258 if (isOffscreen() && !shouldUpdateWhileOffscreen())
3263 void FrameView::scrollToAnchor()
3265 RefPtr<ContainerNode> anchorNode = m_maintainScrollPositionAnchor;
3269 if (!anchorNode->renderer())
3273 if (anchorNode != frame().document() && anchorNode->renderer())
3274 rect = anchorNode->renderer()->anchorRect();
3276 // Scroll nested layers and frames to reveal the anchor.
3277 // Align to the top and to the closest side (this matches other browsers).
3278 if (anchorNode->renderer()->style().isHorizontalWritingMode())
3279 anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
3280 else if (anchorNode->renderer()->style().isFlippedBlocksWritingMode())
3281 anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
3283 anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
3285 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
3286 cache->handleScrolledToAnchor(anchorNode.get());
3288 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
3289 m_maintainScrollPositionAnchor = anchorNode;
3292 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
3294 // No need to update if it's already crashed or known to be missing.
3295 if (embeddedObject.isPluginUnavailable())
3298 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
3300 if (embeddedObject.isSnapshottedPlugIn()) {
3301 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
3302 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
3303 pluginElement.checkSnapshotStatus();
3308 auto weakRenderer = embeddedObject.createWeakPtr();
3310 // FIXME: This could turn into a real virtual dispatch if we defined
3311 // updateWidget(PluginCreationOption) on HTMLElement.
3312 if (is<HTMLPlugInImageElement>(element)) {
3313 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
3314 if (pluginElement.needsCheckForSizeChange()) {
3315 pluginElement.checkSnapshotStatus();
3318 if (pluginElement.needsWidgetUpdate())
3319 pluginElement.updateWidget(CreatePlugins::Yes);
3321 ASSERT_NOT_REACHED();
3323 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
3327 auto ignoreWidgetState = embeddedObject.updateWidgetPosition();
3328 UNUSED_PARAM(ignoreWidgetState);
3331 bool FrameView::updateEmbeddedObjects()
3333 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
3336 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
3338 // Insert a marker for where we should stop.
3339 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
3340 m_embeddedObjectsToUpdate->add(nullptr);
3342 while (!m_embeddedObjectsToUpdate->isEmpty()) {
3343 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
3344 if (!embeddedObject)
3346 updateEmbeddedObject(*embeddedObject);
3349 return m_embeddedObjectsToUpdate->isEmpty();
3352 void FrameView::updateEmbeddedObjectsTimerFired()
3354 RefPtr<FrameView> protectedThis(this);
3355 m_updateEmbeddedObjectsTimer.stop();
3356 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
3357 if (updateEmbeddedObjects())
3362 void FrameView::flushAnyPendingPostLayoutTasks()
3364 if (m_postLayoutTasksTimer.isActive())
3365 performPostLayoutTasks();
3366 if (m_updateEmbeddedObjectsTimer.isActive())
3367 updateEmbeddedObjectsTimerFired();
3370 void FrameView::queuePostLayoutCallback(Function<void()>&& callback)
3372 m_postLayoutCallbackQueue.append(WTFMove(callback));
3375 void FrameView::flushPostLayoutTasksQueue()
3377 if (m_nestedLayoutCount > 1)
3380 if (!m_postLayoutCallbackQueue.size())
3383 Vector<Function<void()>> queue = WTFMove(m_postLayoutCallbackQueue);
3384 for (auto& task : queue)
3388 void FrameView::performPostLayoutTasks()
3390 LOG(Layout, "FrameView %p performPostLayoutTasks", this);
3392 // FIXME: We should not run any JavaScript code in this function.
3394 m_postLayoutTasksTimer.stop();
3396 frame().selection().updateAppearanceAfterLayout();
3398 flushPostLayoutTasksQueue();
3400 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
3401 fireLayoutRelatedMilestonesIfNeeded();
3404 // Only send layout-related delegate callbacks synchronously for the main frame to
3405 // avoid re-entering layout for the main frame while delivering a layout-related delegate
3406 // callback for a subframe.
3407 if (frame().isMainFrame()) {
3408 if (Page* page = frame().page())
3409 page->chrome().client().didLayout();
3413 #if ENABLE(FONT_LOAD_EVENTS)
3414 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
3415 frame().document()->fonts()->didLayout();
3418 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
3419 // with didLayout(LayoutMilestones).
3420 frame().loader().client().dispatchDidLayout();
3422 updateWidgetPositions();
3424 #if ENABLE(CSS_SCROLL_SNAP)
3425 updateSnapOffsets();
3428 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
3429 // is called through the post layout timer.
3430 Ref<FrameView> protectedThis(*this);
3432 m_updateEmbeddedObjectsTimer.startOneShot(0);
3434 if (auto* page = frame().page()) {
3435 if (auto* scrollingCoordinator = page->scrollingCoordinator())
3436 scrollingCoordinator->frameViewLayoutUpdated(*this);
3439 if (RenderView* renderView = this->renderView()) {
3440 if (renderView->usesCompositing())
3441 renderView->compositor().frameViewDidLayout();
3446 sendResizeEventIfNeeded();
3448 updateLayoutViewport();
3449 viewportContentsChanged();
3451 updateScrollSnapState();
3454 IntSize FrameView::sizeForResizeEvent() const
3457 if (m_useCustomSizeForResizeEvent)
3458 return m_customSizeForResizeEvent;
3460 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
3461 return fixedLayoutSize();
3462 return visibleContentRectIncludingScrollbars().size();
3465 void FrameView::sendResizeEventIfNeeded()
3467 if (isInRenderTreeLayout() || needsLayout())
3470 RenderView* renderView = this->renderView();
3471 if (!renderView || renderView->printing())
3474 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
3477 IntSize currentSize = sizeForResizeEvent();
3478 float currentZoomFactor = renderView->style().zoom();
3480 if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor)
3483 m_lastViewportSize = currentSize;
3484 m_lastZoomFactor = currentZoomFactor;
3490 // Don't send the resize event if the document is loading. Some pages automatically reload
3491 // when the window is resized; Safari on iOS often resizes the window while setting up its
3492 // viewport. This obviously can cause problems.
3493 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
3494 if (documentLoader->isLoadingInAPISense())
3499 bool isMainFrame = frame().isMainFrame();
3500 bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize;
3502 Ref<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
3503 if (canSendResizeEventSynchronously)
3504 frame().document()->dispatchWindowEvent(resizeEvent);
3506 // FIXME: Queueing this event for an unpredictable time in the future seems
3507 // intrinsically racy. By the time this resize event fires, the frame might
3508 // be resized again, so we could end up with two resize events for the same size.
3509 frame().document()->enqueueWindowEvent(WTFMove(resizeEvent));
3512 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
3513 if (Page* page = frame().page()) {
3514 if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient())
3515 inspectorClient->didResizeMainFrame(&frame());
3520 void FrameView::willStartLiveResize()
3522 ScrollView::willStartLiveResize();
3523 adjustTiledBackingCoverage();
3526 void FrameView::willEndLiveResize()
3528 ScrollView::willEndLiveResize();
3529 adjustTiledBackingCoverage();
3532 void FrameView::autoSizeIfEnabled()
3534 if (!m_shouldAutoSize)
3540 LOG(Layout, "FrameView %p autoSizeIfEnabled", this);
3542 SetForScope<bool> changeInAutoSize(m_inAutoSize, true);
3544 Document* document = frame().document();
3548 RenderView* documentView = document->renderView();
3549 Element* documentElement = document->documentElement();
3550 if (!documentView || !documentElement)
3554 convertSubtreeLayoutToFullLayout();
3555 // Start from the minimum size and allow it to grow.
3556 resize(m_minAutoSize.width(), m_minAutoSize.height());
3558 IntSize size = frameRect().size();
3560 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
3561 // which may result in a height change during the second iteration.
3562 for (int i = 0; i < 2; i++) {
3563 // Update various sizes including contentsSize, scrollHeight, etc.
3564 document->updateLayoutIgnorePendingStylesheets();
3565 int width = documentView->minPreferredLogicalWidth();
3566 int height = documentView->documentRect().height();
3567 IntSize newSize(width, height);
3569 // Check to see if a scrollbar is needed for a given dimension and
3570 // if so, increase the other dimension to account for the scrollbar.
3571 // Since the dimensions are only for the view rectangle, once a
3572 // dimension exceeds the maximum, there is no need to increase it further.
3573 if (newSize.width() > m_maxAutoSize.width()) {
3574 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
3575 if (!localHorizontalScrollbar)
3576 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
3577 newSize.expand(0, localHorizontalScrollbar->occupiedHeight());
3579 // Don't bother checking for a vertical scrollbar because the width is at
3580 // already greater the maximum.
3581 } else if (newSize.height() > m_maxAutoSize.height()) {
3582 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
3583 if (!localVerticalScrollbar)
3584 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
3585 newSize.expand(localVerticalScrollbar->occupiedWidth(), 0);
3587 // Don't bother checking for a horizontal scrollbar because the height is
3588 // already greater the maximum.
3591 // Ensure the size is at least the min bounds.
3592 newSize = newSize.expandedTo(m_minAutoSize);
3594 // Bound the dimensions by the max bounds and determine what scrollbars to show.
3595 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
3596 if (newSize.width() > m_maxAutoSize.width()) {
3597 newSize.setWidth(m_maxAutoSize.width());
3598 horizonalScrollbarMode = ScrollbarAlwaysOn;
3600 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
3601 if (newSize.height() > m_maxAutoSize.height()) {
3602 newSize.setHeight(m_maxAutoSize.height());
3603 verticalScrollbarMode = ScrollbarAlwaysOn;
3606 if (newSize == size)
3609 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
3610 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
3611 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
3612 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
3615 // The first time around, resize to the minimum height again; otherwise,
3616 // on pages (e.g. quirks mode) where the body/document resize to the view size,
3617 // we'll end up not shrinking back down after resizing to the computed preferred width.
3618 resize(newSize.width(), i ? newSize.height() : m_minAutoSize.height());
3619 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
3620 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
3621 setVerticalScrollbarLock(false);
3622 setHorizontalScrollbarLock(false);
3623 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
3626 m_autoSizeContentSize = contentsSize();
3628 if (m_autoSizeFixedMinimumHeight) {
3629 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
3630 document->updateLayoutIgnorePendingStylesheets();
3633 m_didRunAutosize = true;
3636 void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
3638 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
3641 m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
3646 RenderElement* FrameView::viewportRenderer() const
3648 if (m_viewportRendererType == ViewportRendererType::None)
3651 auto* document = frame().document();
3655 if (m_viewportRendererType == ViewportRendererType::Document) {
3656 auto* documentElement = document->documentElement();
3657 if (!documentElement)
3659 return documentElement->renderer();
3662 if (m_viewportRendererType == ViewportRendererType::Body) {
3663 auto* body = document->body();
3666 return body->renderer();
3669 ASSERT_NOT_REACHED();
3673 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
3675 auto* viewportRenderer = this->viewportRenderer();
3676 if (!viewportRenderer)
3679 if (m_overflowStatusDirty) {
3680 m_horizontalOverflow = horizontalOverflow;
3681 m_verticalOverflow = verticalOverflow;
3682 m_overflowStatusDirty = false;
3686 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
3687 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
3689 if (horizontalOverflowChanged || verticalOverflowChanged) {
3690 m_horizontalOverflow = horizontalOverflow;
3691 m_verticalOverflow = verticalOverflow;
3693 Ref<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
3694 verticalOverflowChanged, verticalOverflow);
3695 overflowEvent->setTarget(viewportRenderer->element());
3697 frame().document()->enqueueOverflowEvent(WTFMove(overflowEvent));
3701 const Pagination& FrameView::pagination() const
3703 if (m_pagination != Pagination())
3704 return m_pagination;
3706 if (frame().isMainFrame()) {
3707 if (Page* page = frame().page())
3708 return page->pagination();
3711 return m_pagination;
3714 void FrameView::setPagination(const Pagination& pagination)
3716 if (m_pagination == pagination)
3719 m_pagination = pagination;
3721 frame().document()->styleScope().didChangeStyleSheetEnvironment();
3724 IntRect FrameView::windowClipRect() const
3726 ASSERT(frame().view() == this);
3728 if (m_cachedWindowClipRect)
3729 return *m_cachedWindowClipRect;
3731 if (paintsEntireContents())
3732 return contentsToWindow(IntRect(IntPoint(), totalContentsSize()));
3734 // Set our clip rect to be our contents.
3735 IntRect clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect));
3737 if (!frame().ownerElement())
3740 // Take our owner element and get its clip rect.
3741 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
3742 if (FrameView* parentView = ownerElement->document().view())
3743 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
3747 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
3749 // The renderer can sometimes be null when style="display:none" interacts
3750 // with external content and plugins.
3751 if (!ownerElement->renderer())
3752 return windowClipRect();
3754 // If we have no layer, just return our window clip rect.
3755 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
3756 if (!enclosingLayer)
3757 return windowClipRect();
3759 // Apply the clip from the layer.
3761 if (clipToLayerContents)
3762 clipRect = snappedIntRect(enclosingLayer->childrenClipRect());
3764 clipRect = snappedIntRect(enclosingLayer->selfClipRect());
3765 clipRect = contentsToWindow(clipRect);
3766 return intersection(clipRect, windowClipRect());
3769 bool FrameView::isActive() const
3771 Page* page = frame().page();
3772 return page && page->focusController().isActive();
3775 bool FrameView::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
3777 Page* page = frame().page();
3778 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
3781 void FrameView::scrollTo(const ScrollPosition& newPosition)
3783 IntPoint oldPosition = scrollPosition();
3784 ScrollView::scrollTo(newPosition);
3785 if (oldPosition != scrollPosition())
3786 scrollPositionChanged(oldPosition, scrollPosition());
3788 didChangeScrollOffset();
3791 float FrameView::adjustScrollStepForFixedContent(float step, ScrollbarOrientation orientation, ScrollGranularity granularity)
3793 if (granularity != ScrollByPage || orientation == HorizontalScrollbar)
3796 TrackedRendererListHashSet* positionedObjects = nullptr;
3797 if (RenderView* root = frame().contentRenderer()) {
3798 if (!root->hasPositionedObjects())
3800 positionedObjects = root->positionedObjects();
3803 FloatRect unobscuredContentRect = this->unobscuredContentRect();
3804 float topObscuredArea = 0;
3805 float bottomObscuredArea = 0;
3806 for (const auto& positionedObject : *positionedObjects) {
3807 const RenderStyle& style = positionedObject->style();
3808 if (style.position() != FixedPosition || style.visibility() == HIDDEN || !style.opacity())
3811 FloatQuad contentQuad = positionedObject->absoluteContentQuad();
3812 if (!contentQuad.isRectilinear())
3815 FloatRect contentBoundingBox = contentQuad.boundingBox();
3816 FloatRect fixedRectInView = intersection(unobscuredContentRect, contentBoundingBox);
3818 if (fixedRectInView.width() < unobscuredContentRect.width())
3821 if (fixedRectInView.y() == unobscuredContentRect.y())
3822 topObscuredArea = std::max(topObscuredArea, fixedRectInView.height());
3823 else if (fixedRectInView.maxY() == unobscuredContentRect.maxY())
3824 bottomObscuredArea = std::max(bottomObscuredArea, fixedRectInView.height());
3827 return Scrollbar::pageStep(unobscuredContentRect.height(), unobscuredContentRect.height() - topObscuredArea - bottomObscuredArea);
3830 void FrameView::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
3832 // Add in our offset within the FrameView.
3833 IntRect dirtyRect = rect;
3834 dirtyRect.moveBy(scrollbar.location());
3835 invalidateRect(dirtyRect);
3838 float FrameView::visibleContentScaleFactor() const
3840 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3843 Page* page = frame().page();
3847 return page->pageScaleFactor();
3850 void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3852 if (!frame().isMainFrame())
3855 if (Page* page = frame().page())
3856 page->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3859 ScrollableArea* FrameView::enclosingScrollableArea() const
3861 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3865 IntRect FrameView::scrollableAreaBoundingBox(bool*) const
3867 RenderWidget* ownerRenderer = frame().ownerRenderer();
3871 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3874 bool FrameView::isScrollable(Scrollability definitionOfScrollable)
3877 // 1) If there an actual overflow.
3878 // 2) display:none or visibility:hidden set to self or inherited.
3879 // 3) overflow{-x,-y}: hidden;
3880 // 4) scrolling: no;
3882 bool requiresActualOverflowToBeConsideredScrollable = !frame().isMainFrame() || definitionOfScrollable != Scrollability::ScrollableOrRubberbandable;
3883 #if !ENABLE(RUBBER_BANDING)
3884 requiresActualOverflowToBeConsideredScrollable = true;
3888 if (requiresActualOverflowToBeConsideredScrollable) {
3889 IntSize totalContentsSize = this->totalContentsSize();
3890 IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size();
3891 if (totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width())
3896 HTMLFrameOwnerElement* owner = frame().ownerElement();
3897 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3901 ScrollbarMode horizontalMode;
3902 ScrollbarMode verticalMode;
3903 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3904 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3910 bool FrameView::isScrollableOrRubberbandable()
3912 return isScrollable(Scrollability::ScrollableOrRubberbandable);
3915 bool FrameView::hasScrollableOrRubberbandableAncestor()
3917 if (frame().isMainFrame())
3918 return isScrollableOrRubberbandable();
3920 for (FrameView* parent = this->parentFrameView(); parent; parent = parent->parentFrameView()) {
3921 Scrollability frameScrollability = parent->frame().isMainFrame() ? Scrollability::ScrollableOrRubberbandable : Scrollability::Scrollable;
3922 if (parent->isScrollable(frameScrollability))
3929 void FrameView::updateScrollableAreaSet()
3931 // That ensures that only inner frames are cached.
3932 FrameView* parentFrameView = this->parentFrameView();
3933 if (!parentFrameView)
3936 if (!isScrollable()) {
3937 parentFrameView->removeScrollableArea(this);
3941 parentFrameView->addScrollableArea(this);
3944 bool FrameView::shouldSuspendScrollAnimations() const
3946 return frame().loader().state() != FrameStateComplete;
3949 void FrameView::scrollbarStyleChanged(ScrollbarStyle newStyle, bool forceUpdate)
3951 if (!frame().isMainFrame())
3954 if (Page* page = frame().page())
3955 page->chrome().client().recommendedScrollbarStyleDidChange(newStyle);
3957 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
3960 void FrameView::notifyPageThatContentAreaWillPaint() const
3962 Page* page = frame().page();
3966 contentAreaWillPaint();
3968 if (!m_scrollableAreas)
3971 for (auto& scrollableArea : *m_scrollableAreas)
3972 scrollableArea->contentAreaWillPaint();
3975 bool FrameView::scrollAnimatorEnabled() const
3977 #if ENABLE(SMOOTH_SCROLLING)
3978 if (Page* page = frame().page())
3979 return page->settings().scrollAnimatorEnabled();
3985 #if ENABLE(DASHBOARD_SUPPORT)
3986 void FrameView::updateAnnotatedRegions()
3988 Document* document = frame().document();
3989 if (!document->hasAnnotatedRegions())
3991 Vector<AnnotatedRegionValue> newRegions;
3992 document->renderBox()->collectAnnotatedRegions(newRegions);
3993 if (newRegions == document->annotatedRegions())
3995 document->setAnnotatedRegions(newRegions);
3996 Page* page = frame().page();
3999 page->chrome().client().annotatedRegionsChanged();
4003 void FrameView::updateScrollCorner()
4005 RenderElement* renderer = nullptr;
4006 std::unique_ptr<RenderStyle> cornerStyle;
4007 IntRect cornerRect = scrollCornerRect();
4009 if (!cornerRect.isEmpty()) {
4010 // Try the <body> element first as a scroll corner source.
4011 Document* doc = frame().document();
4012 Element* body = doc ? doc->bodyOrFrameset() : nullptr;
4013 if (body && body->renderer()) {
4014 renderer = body->renderer();
4015 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
4019 // If the <body> didn't have a custom style, then the root element might.
4020 Element* docElement = doc ? doc->documentElement() : nullptr;
4021 if (docElement && docElement->renderer()) {
4022 renderer = docElement->renderer();
4023 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
4028 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
4029 if (RenderWidget* renderer = frame().ownerRenderer())
4030 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
4035 m_scrollCorner = nullptr;
4037 if (!m_scrollCorner) {
4038 m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer->document(), WTFMove(*cornerStyle));
4039 m_scrollCorner->initializeStyle();
4041 m_scrollCorner->setStyle(WTFMove(*cornerStyle));
4042 invalidateScrollCorner(cornerRect);
4045 ScrollView::updateScrollCorner();
4048 void FrameView::paintScrollCorner(GraphicsContext& context, const IntRect& cornerRect)
4050 if (context.updatingControlTints()) {
4051 updateScrollCorner();
4055 if (m_scrollCorner) {
4056 if (frame().isMainFrame())
4057 context.fillRect(cornerRect, baseBackgroundColor());
4058 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
4062 ScrollView::paintScrollCorner(context, cornerRect);
4065 void FrameView::paintScrollbar(GraphicsContext& context, Scrollbar& bar, const IntRect& rect)
4067 if (bar.isCustomScrollbar() && frame().isMainFrame()) {
4068 IntRect toFill = bar.frameRect();
4069 toFill.intersect(rect);
4070 context.fillRect(toFill, baseBackgroundColor());
4073 ScrollView::paintScrollbar(context, bar, rect);
4076 Color FrameView::documentBackgroundColor() const
4078 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
4079 // the document and the body against the base background color of the frame view.
4080 // Background images are unfortunately impractical to include.
4082 // Return invalid Color objects whenever there is insufficient information.
4083 if (!frame().document())
4086 auto* htmlElement = frame().document()->documentElement();
4087 auto* bodyElement = frame().document()->bodyOrFrameset();
4089 // Start with invalid colors.
4090 Color htmlBackgroundColor;
4091 Color bodyBackgroundColor;
4092 if (htmlElement && htmlElement->renderer())
4093 htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
4094 if (bodyElement && bodyElement->renderer())
4095 bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
4097 if (!bodyBackgroundColor.isValid()) {
4098 if (!htmlBackgroundColor.isValid())
4100 return baseBackgroundColor().blend(htmlBackgroundColor);
4103 if (!htmlBackgroundColor.isValid())
4104 return baseBackgroundColor().blend(bodyBackgroundColor);
4106 // We take the aggregate of the base background color
4107 // the <html> background color, and the <body>
4108 // background color to find the document color. The
4109 // addition of the base background color is not
4110 // technically part of the document background, but it
4111 // otherwise poses problems when the aggregate is not
4113 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor);
4116 bool FrameView::hasCustomScrollbars() const
4118 for (auto& widget : children()) {
4119 if (is<FrameView>(*widget)) {
4120 if (downcast<FrameView>(*widget).hasCustomScrollbars())
4122 } else if (is<Scrollbar>(*widget)) {
4123 if (downcast<Scrollbar>(*widget).isCustomScrollbar())
4131 FrameView* FrameView::parentFrameView() const
4136 if (Frame* parentFrame = frame().tree().parent())
4137 return parentFrame->view();
4142 bool FrameView::isInChildFrameWithFrameFlattening() const
4144 if (!frameFlatteningEnabled())
4150 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
4154 if (!ownerElement->renderWidget())
4157 // Frame flattening applies when the owner element is either in a frameset or
4158 // an iframe with flattening parameters.
4159 if (is<HTMLIFrameElement>(*ownerElement))
4160 return downcast<RenderIFrame>(*ownerElement->renderWidget()).flattenFrame();
4162 if (is<HTMLFrameElement>(*ownerElement))
4168 void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree)
4170 // When we start a layout at the child level as opposed to the topmost frame view and this child
4171 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
4172 // will hit this view eventually.
4173 FrameView* parentView = parentFrameView();
4177 // In the middle of parent layout, no need to restart from topmost.
4178 if (parentView->m_nestedLayoutCount)
4181 // Parent tree is clean. Starting layout from it would have no effect.
4182 if (!parentView->needsLayout())
4185 while (parentView->parentFrameView())
4186 parentView = parentView->parentFrameView();
4188 LOG(Layout, " frame flattening, starting from root");
4189 parentView->layout(allowSubtree);
4192 void FrameView::updateControlTints()
4194 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
4195 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
4196 // This is only done if the theme supports control tinting. It's up to the theme and platform
4197 // to define when controls get the tint and to call this function when that changes.
4199 // Optimize the common case where we bring a window to the front while it's still empty.
4200 if (frame().document()->url().isEmpty())
4203 // As noted above, this is a "fake" paint, so we should pause counting relevant repainted objects.
4204 Page* page = frame().page();
4205 bool isCurrentlyCountingRelevantRepaintedObject = false;
4207 isCurrentlyCountingRelevantRepaintedObject = page->isCountingRelevantRepaintedObjects();
4208 page->setIsCountingRelevantRepaintedObjects(false);
4211 RenderView* renderView = this->renderView();
4212 if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars())
4213 paintControlTints();
4216 page->setIsCountingRelevantRepaintedObjects(isCurrentlyCountingRelevantRepaintedObject);
4219 void FrameView::paintControlTints()
4224 GraphicsContext context(GraphicsContext::NonPaintingReasons::UpdatingControlTints);
4225 if (platformWidget()) {
4226 // FIXME: consult paintsEntireContents().
4227 paintContents(context, visibleContentRect(LegacyIOSDocumentVisibleRect));
4229 paint(context, frameRect());
4232 bool FrameView::wasScrolledByUser() const
4234 return m_wasScrolledByUser;
4237 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
4239 if (m_inProgrammaticScroll)
4241 m_maintainScrollPositionAnchor = nullptr;
4242 if (m_wasScrolledByUser == wasScrolledByUser)
4244 m_wasScrolledByUser = wasScrolledByUser;
4245 if (frame().isMainFrame())
4246 updateLayerFlushThrottling();
4247 adjustTiledBackingCoverage();
4250 void FrameView::willPaintContents(GraphicsContext& context, const IntRect&, PaintingState& paintingState)
4252 Document* document = frame().document();
4254 if (!context.paintingDisabled())
4255 InspectorInstrumentation::willPaint(*renderView());
4257 paintingState.isTopLevelPainter = !sCurrentPaintTimeStamp;
4259 if (paintingState.isTopLevelPainter && MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
4260 LOG(MemoryPressure, "Under memory pressure: %s", WTF_PRETTY_FUNCTION);
4262 // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since
4263 // we might need some live bitmaps on painting.
4264 MemoryCache::singleton().prune();
4267 if (paintingState.isTopLevelPainter)
4268 sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
4270 paintingState.paintBehavior = m_paintBehavior;