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-2017 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 "BackForwardController.h"
32 #include "CSSAnimationController.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 "OverflowEvent.h"
68 #include "PageCache.h"
69 #include "PageOverlayController.h"
70 #include "ProgressTracker.h"
71 #include "RenderEmbeddedObject.h"
72 #include "RenderFullScreen.h"
73 #include "RenderIFrame.h"
74 #include "RenderInline.h"
75 #include "RenderLayer.h"
76 #include "RenderLayerBacking.h"
77 #include "RenderLayerCompositor.h"
78 #include "RenderSVGRoot.h"
79 #include "RenderScrollbar.h"
80 #include "RenderScrollbarPart.h"
81 #include "RenderStyle.h"
82 #include "RenderText.h"
83 #include "RenderTheme.h"
84 #include "RenderView.h"
85 #include "RenderWidget.h"
86 #include "SVGDocument.h"
87 #include "SVGSVGElement.h"
88 #include "ScriptedAnimationController.h"
89 #include "ScrollAnimator.h"
90 #include "ScrollingCoordinator.h"
92 #include "StyleResolver.h"
93 #include "StyleScope.h"
94 #include "TextResourceDecoder.h"
95 #include "TiledBacking.h"
96 #include "WheelEventTestTrigger.h"
97 #include <wtf/text/TextStream.h>
99 #include <wtf/CurrentTime.h>
100 #include <wtf/MemoryPressureHandler.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));
299 if (frame.page() && frame.page()->isVisible())
304 Ref<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
306 Ref<FrameView> view = adoptRef(*new FrameView(frame));
307 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
308 if (frame.page() && frame.page()->isVisible())
313 FrameView::~FrameView()
315 if (m_postLayoutTasksTimer.isActive())
316 m_postLayoutTasksTimer.stop();
318 removeFromAXObjectCache();
321 // Custom scrollbars should already be destroyed at this point
322 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
323 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
325 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
326 setHasVerticalScrollbar(false);
328 ASSERT(!m_scrollCorner);
330 ASSERT(frame().view() != this || !frame().contentRenderer());
333 void FrameView::reset()
335 m_cannotBlitToWindow = false;
336 m_isOverlapped = false;
337 m_contentIsOpaque = false;
338 m_layoutTimer.stop();
339 m_layoutRoot = nullptr;
340 m_delayedLayout = false;
341 m_needsFullRepaint = true;
342 m_layoutSchedulingEnabled = true;
343 m_layoutPhase = OutsideLayout;
344 m_inSynchronousPostLayout = false;
346 m_nestedLayoutCount = 0;
347 m_postLayoutTasksTimer.stop();
348 m_updateEmbeddedObjectsTimer.stop();
349 m_firstLayout = true;
350 m_firstLayoutCallbackPending = false;
351 m_wasScrolledByUser = false;
352 m_safeToPropagateScrollToParent = true;
353 m_delayedScrollEventTimer.stop();
354 m_lastViewportSize = IntSize();
355 m_lastZoomFactor = 1.0f;
356 m_isTrackingRepaints = false;
357 m_trackedRepaintRects.clear();
359 m_paintBehavior = PaintBehaviorNormal;
360 m_isPainting = false;
361 m_visuallyNonEmptyCharacterCount = 0;
362 m_visuallyNonEmptyPixelCount = 0;
363 m_isVisuallyNonEmpty = false;
364 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
365 m_needsDeferredScrollbarsUpdate = false;
366 m_maintainScrollPositionAnchor = nullptr;
369 void FrameView::removeFromAXObjectCache()
371 if (AXObjectCache* cache = axObjectCache()) {
372 if (HTMLFrameOwnerElement* owner = frame().ownerElement())
373 cache->childrenChanged(owner->renderer());
378 void FrameView::resetScrollbars()
380 // Reset the document's scrollbars back to our defaults before we yield the floor.
381 m_firstLayout = true;
382 setScrollbarsSuppressed(true);
383 if (m_canHaveScrollbars)
384 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
386 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
387 setScrollbarsSuppressed(false);
390 void FrameView::resetScrollbarsAndClearContentsSize()
394 setScrollbarsSuppressed(true);
395 setContentsSize(IntSize());
396 setScrollbarsSuppressed(false);
399 void FrameView::init()
403 m_margins = LayoutSize(-1, -1); // undefined
404 m_size = LayoutSize();
406 // Propagate the marginwidth/height and scrolling modes to the view.
407 Element* ownerElement = frame().ownerElement();
408 if (is<HTMLFrameElementBase>(ownerElement)) {
409 HTMLFrameElementBase& frameElement = downcast<HTMLFrameElementBase>(*ownerElement);
410 if (frameElement.scrollingMode() == ScrollbarAlwaysOff)
411 setCanHaveScrollbars(false);
412 LayoutUnit marginWidth = frameElement.marginWidth();
413 LayoutUnit marginHeight = frameElement.marginHeight();
414 if (marginWidth != -1)
415 setMarginWidth(marginWidth);
416 if (marginHeight != -1)
417 setMarginHeight(marginHeight);
420 Page* page = frame().page();
421 if (page && page->chrome().client().shouldPaintEntireContents())
422 setPaintsEntireContents(true);
425 void FrameView::prepareForDetach()
427 detachCustomScrollbars();
428 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
429 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
430 removeFromAXObjectCache();
432 if (frame().page()) {
433 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
434 scrollingCoordinator->willDestroyScrollableArea(*this);
438 void FrameView::detachCustomScrollbars()
440 Scrollbar* horizontalBar = horizontalScrollbar();
441 if (horizontalBar && horizontalBar->isCustomScrollbar())
442 setHasHorizontalScrollbar(false);
444 Scrollbar* verticalBar = verticalScrollbar();
445 if (verticalBar && verticalBar->isCustomScrollbar())
446 setHasVerticalScrollbar(false);
448 m_scrollCorner = nullptr;
451 void FrameView::recalculateScrollbarOverlayStyle()
453 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
454 std::optional<ScrollbarOverlayStyle> clientOverlayStyle = frame().page() ? frame().page()->chrome().client().preferredScrollbarOverlayStyle() : ScrollbarOverlayStyleDefault;
455 if (clientOverlayStyle) {
456 if (clientOverlayStyle.value() != oldOverlayStyle)
457 setScrollbarOverlayStyle(clientOverlayStyle.value());
461 ScrollbarOverlayStyle computedOverlayStyle = ScrollbarOverlayStyleDefault;
463 Color backgroundColor = documentBackgroundColor();
464 if (backgroundColor.isValid()) {
465 // Reduce the background color from RGB to a lightness value
466 // and determine which scrollbar style to use based on a lightness
468 double hue, saturation, lightness;
469 backgroundColor.getHSL(hue, saturation, lightness);
470 if (lightness <= .5 && backgroundColor.isVisible())
471 computedOverlayStyle = ScrollbarOverlayStyleLight;
474 if (oldOverlayStyle != computedOverlayStyle)
475 setScrollbarOverlayStyle(computedOverlayStyle);
478 void FrameView::clear()
480 setCanBlitOnScroll(true);
484 setScrollbarsSuppressed(true);
487 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
488 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
489 if (LegacyTileCache* tileCache = legacyTileCache())
490 tileCache->setTilingMode(LegacyTileCache::Disabled);
495 void FrameView::didReplaceMultipartContent()
497 // Re-enable tile updates that were disabled in clear().
498 if (LegacyTileCache* tileCache = legacyTileCache())
499 tileCache->setTilingMode(LegacyTileCache::Normal);
503 bool FrameView::didFirstLayout() const
505 return !m_firstLayout;
508 void FrameView::invalidateRect(const IntRect& rect)
511 if (auto* page = frame().page())
512 page->chrome().invalidateContentsAndRootView(rect);
516 auto* renderer = frame().ownerRenderer();
520 IntRect repaintRect = rect;
521 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
522 renderer->repaintRectangle(repaintRect);
525 void FrameView::setFrameRect(const IntRect& newRect)
527 Ref<FrameView> protectedThis(*this);
528 IntRect oldRect = frameRect();
529 if (newRect == oldRect)
531 // Every scroll that happens as the result of frame size change is programmatic.
532 SetForScope<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
533 ScrollView::setFrameRect(newRect);
535 updateScrollableAreaSet();
537 if (RenderView* renderView = this->renderView()) {
538 if (renderView->usesCompositing())
539 renderView->compositor().frameViewDidChangeSize();
542 if (frame().isMainFrame())
543 frame().mainFrame().pageOverlayController().didChangeViewSize();
545 viewportContentsChanged();
548 bool FrameView::scheduleAnimation()
550 auto* page = frame().page();
553 page->chrome().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 FrameFlattening FrameView::effectiveFrameFlattening() const
572 // On iOS when async frame scrolling is enabled, it does not make sense to use full frame flattening.
573 // In that case, we just consider that frame flattening is disabled. This allows people to test
574 // frame scrolling on iOS by enabling "Async Frame Scrolling" via the Safari menu.
575 if (frame().settings().asyncFrameScrollingEnabled() && frame().settings().frameFlattening() == FrameFlattening::FullyEnabled)
576 return FrameFlattening::Disabled;
578 return frame().settings().frameFlattening();
581 bool FrameView::frameFlatteningEnabled() const
583 return effectiveFrameFlattening() != FrameFlattening::Disabled;
586 bool FrameView::isFrameFlatteningValidForThisFrame() const
588 if (!frameFlatteningEnabled())
591 HTMLFrameOwnerElement* owner = frame().ownerElement();
595 // Frame flattening is valid only for <frame> and <iframe>.
596 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
599 bool FrameView::avoidScrollbarCreation() const
601 // with frame flattening no subframe can have scrollbars
602 // but we also cannot turn scrollbars off as we determine
603 // our flattening policy using that.
604 return isFrameFlatteningValidForThisFrame();
607 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
609 m_canHaveScrollbars = canHaveScrollbars;
610 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
613 void FrameView::updateCanHaveScrollbars()
617 scrollbarModes(hMode, vMode);
618 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
619 setCanHaveScrollbars(false);
621 setCanHaveScrollbars(true);
624 Ref<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
626 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
627 Document* doc = frame().document();
629 // Try the <body> element first as a scrollbar source.
630 HTMLElement* body = doc ? doc->bodyOrFrameset() : nullptr;
631 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
632 return RenderScrollbar::createCustomScrollbar(*this, orientation, body);
634 // If the <body> didn't have a custom style, then the root element might.
635 Element* docElement = doc ? doc->documentElement() : nullptr;
636 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
637 return RenderScrollbar::createCustomScrollbar(*this, orientation, docElement);
639 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
640 RenderWidget* frameRenderer = frame().ownerRenderer();
641 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
642 return RenderScrollbar::createCustomScrollbar(*this, orientation, nullptr, &frame());
644 // Nobody set a custom style, so we just use a native scrollbar.
645 return ScrollView::createScrollbar(orientation);
648 void FrameView::didRestoreFromPageCache()
650 // When restoring from page cache, the main frame stays in place while subframes get swapped in.
651 // We update the scrollable area set to ensure that scrolling data structures get invalidated.
652 updateScrollableAreaSet();
655 void FrameView::willDestroyRenderTree()
657 detachCustomScrollbars();
658 m_layoutRoot = nullptr;
661 void FrameView::didDestroyRenderTree()
663 ASSERT(!m_layoutRoot);
664 ASSERT(m_widgetsInRenderTree.isEmpty());
666 // If the render tree is destroyed below FrameView::updateEmbeddedObjects(), there will still be a null sentinel in the set.
667 // Everything else should have removed itself as the tree was felled.
668 ASSERT(!m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty() || (m_embeddedObjectsToUpdate->size() == 1 && m_embeddedObjectsToUpdate->first() == nullptr));
670 ASSERT(!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty());
671 ASSERT(!m_slowRepaintObjects || m_slowRepaintObjects->isEmpty());
673 ASSERT(!frame().animation().hasAnimations());
676 void FrameView::setContentsSize(const IntSize& size)
678 if (size == contentsSize())
681 m_deferSetNeedsLayoutCount++;
683 ScrollView::setContentsSize(size);
686 Page* page = frame().page();
690 updateScrollableAreaSet();
692 page->chrome().contentsSizeChanged(frame(), size); // Notify only.
694 if (frame().isMainFrame()) {
695 frame().mainFrame().pageOverlayController().didChangeDocumentSize();
696 PageCache::singleton().markPagesForContentsSizeChanged(*page);
699 ASSERT(m_deferSetNeedsLayoutCount);
700 m_deferSetNeedsLayoutCount--;
702 if (!m_deferSetNeedsLayoutCount)
703 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
706 void FrameView::adjustViewSize()
708 RenderView* renderView = this->renderView();
712 ASSERT(frame().view() == this);
714 const IntRect rect = renderView->documentRect();
715 const IntSize& size = rect.size();
716 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
718 LOG_WITH_STREAM(Layout, stream << "FrameView " << this << " adjustViewSize: unscaled document rect changed to " << renderView->unscaledDocumentRect() << " (scaled to " << size << ")");
720 setContentsSize(size);
723 void FrameView::applyOverflowToViewport(const RenderElement& renderer, ScrollbarMode& hMode, ScrollbarMode& vMode)
725 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
726 // overflow:hidden and overflow:scroll on <body> as applying to the document's
727 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
728 // use the root element.
730 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
731 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
734 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
736 EOverflow overflowX = renderer.style().overflowX();
737 EOverflow overflowY = renderer.style().overflowY();
739 if (is<RenderSVGRoot>(renderer)) {
740 // FIXME: evaluate if we can allow overflow for these cases too.
741 // Overflow is always hidden when stand-alone SVG documents are embedded.
742 if (downcast<RenderSVGRoot>(renderer).isEmbeddedThroughFrameContainingSVGDocument()) {
751 hMode = ScrollbarAuto;
753 hMode = ScrollbarAlwaysOff;
756 hMode = ScrollbarAlwaysOn;
759 hMode = ScrollbarAuto;
762 // Don't set it at all.
769 vMode = ScrollbarAuto;
771 vMode = ScrollbarAlwaysOff;
774 vMode = ScrollbarAlwaysOn;
777 vMode = ScrollbarAuto;
780 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
785 void FrameView::applyPaginationToViewport()
787 auto* document = frame().document();
788 auto* documentElement = document ? document->documentElement() : nullptr;
789 if (!documentElement || !documentElement->renderer()) {
790 setPagination(Pagination());
794 auto& documentRenderer = *documentElement->renderer();
795 auto* documentOrBodyRenderer = &documentRenderer;
797 auto* body = document->body();
798 if (body && body->renderer()) {
799 documentOrBodyRenderer = documentRenderer.style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(*documentElement) ?
800 body->renderer() : &documentRenderer;
803 Pagination pagination;
804 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
805 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
806 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
807 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
809 setPagination(pagination);
812 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
814 m_viewportRendererType = ViewportRendererType::None;
816 const HTMLFrameOwnerElement* owner = frame().ownerElement();
817 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
818 hMode = ScrollbarAlwaysOff;
819 vMode = ScrollbarAlwaysOff;
823 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
824 hMode = ScrollbarAuto;
825 vMode = ScrollbarAuto;
827 hMode = ScrollbarAlwaysOff;
828 vMode = ScrollbarAlwaysOff;
834 auto* document = frame().document();
838 auto* documentElement = document->documentElement();
839 if (!documentElement)
842 auto* bodyOrFrameset = document->bodyOrFrameset();
843 auto* rootRenderer = documentElement->renderer();
844 if (!bodyOrFrameset || !bodyOrFrameset->renderer()) {
846 applyOverflowToViewport(*rootRenderer, hMode, vMode);
847 m_viewportRendererType = ViewportRendererType::Document;
852 if (is<HTMLFrameSetElement>(*bodyOrFrameset) && !frameFlatteningEnabled()) {
853 vMode = ScrollbarAlwaysOff;
854 hMode = ScrollbarAlwaysOff;
858 if (is<HTMLBodyElement>(*bodyOrFrameset) && rootRenderer) {
859 // It's sufficient to just check the X overflow,
860 // since it's illegal to have visible in only one direction.
861 if (rootRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(documentElement)) {
862 auto* bodyRenderer = bodyOrFrameset->renderer();
864 applyOverflowToViewport(*bodyRenderer, hMode, vMode);
865 m_viewportRendererType = ViewportRendererType::Body;
868 applyOverflowToViewport(*rootRenderer, hMode, vMode);
869 m_viewportRendererType = ViewportRendererType::Document;
874 void FrameView::willRecalcStyle()
876 RenderView* renderView = this->renderView();
880 renderView->compositor().willRecalcStyle();
883 bool FrameView::updateCompositingLayersAfterStyleChange()
885 RenderView* renderView = this->renderView();
889 // If we expect to update compositing after an incipient layout, don't do so here.
890 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
893 return renderView->compositor().didRecalcStyleWithNoPendingLayout();
896 void FrameView::updateCompositingLayersAfterLayout()
898 RenderView* renderView = this->renderView();
902 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
903 renderView->compositor().cacheAcceleratedCompositingFlags();
904 renderView->compositor().updateCompositingLayers(CompositingUpdateType::AfterLayout);
907 void FrameView::clearBackingStores()
909 RenderView* renderView = this->renderView();
913 RenderLayerCompositor& compositor = renderView->compositor();
914 ASSERT(compositor.inCompositingMode());
915 compositor.enableCompositingMode(false);
916 compositor.clearBackingForAllLayers();
919 GraphicsLayer* FrameView::layerForScrolling() const
921 RenderView* renderView = this->renderView();
924 return renderView->compositor().scrollLayer();
927 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
929 RenderView* renderView = this->renderView();
932 return renderView->compositor().layerForHorizontalScrollbar();
935 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
937 RenderView* renderView = this->renderView();
940 return renderView->compositor().layerForVerticalScrollbar();
943 GraphicsLayer* FrameView::layerForScrollCorner() const
945 RenderView* renderView = this->renderView();
948 return renderView->compositor().layerForScrollCorner();
951 TiledBacking* FrameView::tiledBacking() const
953 RenderView* renderView = this->renderView();
957 RenderLayerBacking* backing = renderView->layer()->backing();
961 return backing->tiledBacking();
964 uint64_t FrameView::scrollLayerID() const
966 RenderView* renderView = this->renderView();
970 RenderLayerBacking* backing = renderView->layer()->backing();
974 return backing->scrollingNodeIDForRole(Scrolling);
977 ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
979 RenderView* renderView = this->renderView();
983 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
986 #if ENABLE(RUBBER_BANDING)
987 GraphicsLayer* FrameView::layerForOverhangAreas() const
989 RenderView* renderView = this->renderView();
992 return renderView->compositor().layerForOverhangAreas();
995 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
997 RenderView* renderView = this->renderView();
1001 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
1004 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
1006 RenderView* renderView = this->renderView();
1010 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
1013 #endif // ENABLE(RUBBER_BANDING)
1015 #if ENABLE(CSS_SCROLL_SNAP)
1016 void FrameView::updateSnapOffsets()
1018 if (!frame().document())
1021 // FIXME: Should we allow specifying snap points through <html> tags too?
1022 HTMLElement* body = frame().document()->bodyOrFrameset();
1023 if (!renderView() || !body || !body->renderer())
1026 updateSnapOffsetsForScrollableArea(*this, *body, *renderView(), body->renderer()->style());
1029 bool FrameView::isScrollSnapInProgress() const
1031 if (scrollbarsSuppressed())
1034 // If the scrolling thread updates the scroll position for this FrameView, then we should return
1035 // ScrollingCoordinator::isScrollSnapInProgress().
1036 if (Page* page = frame().page()) {
1037 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
1038 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this))
1039 return scrollingCoordinator->isScrollSnapInProgress();
1043 // If the main thread updates the scroll position for this FrameView, we should return
1044 // ScrollAnimator::isScrollSnapInProgress().
1045 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1046 return scrollAnimator->isScrollSnapInProgress();
1051 void FrameView::updateScrollingCoordinatorScrollSnapProperties() const
1053 renderView()->compositor().updateScrollSnapPropertiesWithFrameView(*this);
1057 bool FrameView::flushCompositingStateForThisFrame(const Frame& rootFrameForFlush)
1059 RenderView* renderView = this->renderView();
1061 return true; // We don't want to keep trying to update layers if we have no renderer.
1063 ASSERT(frame().view() == this);
1065 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
1066 // layer content to occur before layout has happened, which will cause paintContents() to bail.
1071 if (LegacyTileCache* tileCache = legacyTileCache())
1072 tileCache->doPendingRepaints();
1075 renderView->compositor().flushPendingLayerChanges(&rootFrameForFlush == m_frame.ptr());
1079 void FrameView::setNeedsOneShotDrawingSynchronization()
1081 if (Page* page = frame().page())
1082 page->chrome().client().setNeedsOneShotDrawingSynchronization();
1085 GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
1087 // To find the Widget that corresponds with platformWidget we have to do a linear
1088 // search of our child widgets.
1089 const Widget* foundWidget = nullptr;
1090 for (auto& widget : children()) {
1091 if (widget->platformWidget() != platformWidget)
1093 foundWidget = widget.ptr();
1100 auto* renderWidget = RenderWidget::find(*foundWidget);
1104 auto* widgetLayer = renderWidget->layer();
1105 if (!widgetLayer || !widgetLayer->isComposited())
1108 return widgetLayer->backing()->parentForSublayers();
1111 void FrameView::scheduleLayerFlushAllowingThrottling()
1113 RenderView* view = this->renderView();
1116 view->compositor().scheduleLayerFlush(true /* canThrottle */);
1119 LayoutRect FrameView::fixedScrollableAreaBoundsInflatedForScrolling(const LayoutRect& uninflatedBounds) const
1121 LayoutPoint scrollPosition;
1122 LayoutSize topLeftExpansion;
1123 LayoutSize bottomRightExpansion;
1125 if (frame().settings().visualViewportEnabled()) {
1126 // FIXME: this is wrong under zooming; uninflatedBounds is scaled but the scroll positions are not.
1127 scrollPosition = layoutViewportRect().location();
1128 topLeftExpansion = scrollPosition - unscaledMinimumScrollPosition();
1129 bottomRightExpansion = unscaledMaximumScrollPosition() - scrollPosition;
1131 scrollPosition = scrollPositionRespectingCustomFixedPosition();
1132 topLeftExpansion = scrollPosition - minimumScrollPosition();
1133 bottomRightExpansion = maximumScrollPosition() - scrollPosition;
1136 return LayoutRect(uninflatedBounds.location() - topLeftExpansion, uninflatedBounds.size() + topLeftExpansion + bottomRightExpansion);
1139 LayoutPoint FrameView::scrollPositionRespectingCustomFixedPosition() const
1142 if (!frame().settings().visualViewportEnabled())
1143 return useCustomFixedPositionLayoutRect() ? customFixedPositionLayoutRect().location() : scrollPosition();
1146 return scrollPositionForFixedPosition();
1149 void FrameView::setHeaderHeight(int headerHeight)
1152 ASSERT(frame().isMainFrame());
1153 m_headerHeight = headerHeight;
1155 if (RenderView* renderView = this->renderView())
1156 renderView->setNeedsLayout();
1159 void FrameView::setFooterHeight(int footerHeight)
1162 ASSERT(frame().isMainFrame());
1163 m_footerHeight = footerHeight;
1165 if (RenderView* renderView = this->renderView())
1166 renderView->setNeedsLayout();
1169 float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const
1171 if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset)
1172 return platformTopContentInset();
1174 if (!frame().isMainFrame())
1177 Page* page = frame().page();
1178 return page ? page->topContentInset() : 0;
1181 void FrameView::topContentInsetDidChange(float newTopContentInset)
1183 RenderView* renderView = this->renderView();
1187 if (platformWidget())
1188 platformSetTopContentInset(newTopContentInset);
1191 // Every scroll that happens as the result of content inset change is programmatic.
1192 SetForScope<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1193 updateScrollbars(scrollPosition());
1194 if (renderView->usesCompositing())
1195 renderView->compositor().frameViewDidChangeSize();
1197 if (TiledBacking* tiledBacking = this->tiledBacking())
1198 tiledBacking->setTopContentInset(newTopContentInset);
1201 void FrameView::topContentDirectionDidChange()
1203 m_needsDeferredScrollbarsUpdate = true;
1206 void FrameView::handleDeferredScrollbarsUpdateAfterDirectionChange()
1208 if (!m_needsDeferredScrollbarsUpdate)
1211 m_needsDeferredScrollbarsUpdate = false;
1213 ASSERT(m_layoutPhase == InPostLayerPositionsUpdatedAfterLayout);
1214 updateScrollbars(scrollPosition());
1215 positionScrollbarLayers();
1218 bool FrameView::hasCompositedContent() const
1220 if (RenderView* renderView = this->renderView())
1221 return renderView->compositor().inCompositingMode();
1225 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
1226 void FrameView::enterCompositingMode()
1228 if (RenderView* renderView = this->renderView()) {
1229 renderView->compositor().enableCompositingMode();
1231 renderView->compositor().scheduleCompositingLayerUpdate();
1235 bool FrameView::isEnclosedInCompositingLayer() const
1237 auto frameOwnerRenderer = frame().ownerRenderer();
1238 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1241 if (FrameView* parentView = parentFrameView())
1242 return parentView->isEnclosedInCompositingLayer();
1246 bool FrameView::flushCompositingStateIncludingSubframes()
1249 InspectorInstrumentation::willComposite(frame());
1252 bool allFramesFlushed = flushCompositingStateForThisFrame(frame());
1254 for (Frame* child = frame().tree().firstRenderedChild(); child; child = child->tree().traverseNextRendered(m_frame.ptr())) {
1257 bool flushed = child->view()->flushCompositingStateForThisFrame(frame());
1258 allFramesFlushed &= flushed;
1260 return allFramesFlushed;
1263 bool FrameView::isSoftwareRenderable() const
1265 RenderView* renderView = this->renderView();
1266 return !renderView || !renderView->compositor().has3DContent();
1269 void FrameView::setIsInWindow(bool isInWindow)
1271 if (RenderView* renderView = this->renderView())
1272 renderView->setIsInWindow(isInWindow);
1275 inline void FrameView::forceLayoutParentViewIfNeeded()
1277 RenderWidget* ownerRenderer = frame().ownerRenderer();
1281 RenderBox* contentBox = embeddedContentBox();
1285 auto& svgRoot = downcast<RenderSVGRoot>(*contentBox);
1286 if (svgRoot.everHadLayout() && !svgRoot.needsLayout())
1289 LOG(Layout, "FrameView %p forceLayoutParentViewIfNeeded scheduling layout on parent FrameView %p", this, &ownerRenderer->view().frameView());
1291 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1292 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1293 // embeddedContentBox() returns nullptr, as long as the embedded document isn't loaded yet. Before
1294 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1295 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1296 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1297 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1299 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1300 ownerRenderer->view().frameView().scheduleRelayout();
1303 void FrameView::layout(bool allowSubtree)
1305 ASSERT_WITH_SECURITY_IMPLICATION(!frame().document()->inRenderTreeUpdate());
1307 LOG(Layout, "FrameView %p (%dx%d) layout, main frameview %d, allowSubtree=%d", this, size().width(), size().height(), frame().isMainFrame(), allowSubtree);
1308 if (isInRenderTreeLayout()) {
1309 LOG(Layout, " in layout, bailing");
1313 if (layoutDisallowed()) {
1314 LOG(Layout, " layout is disallowed, bailing");
1318 // Protect the view from being deleted during layout (in recalcStyle).
1319 Ref<FrameView> protectedThis(*this);
1321 // Many of the tasks performed during layout can cause this function to be re-entered,
1322 // so save the layout phase now and restore it on exit.
1323 SetForScope<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1325 // Every scroll that happens during layout is programmatic.
1326 SetForScope<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1328 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1330 if (inChildFrameLayoutWithFrameFlattening) {
1331 if (!m_frameFlatteningViewSizeForMediaQuery) {
1332 LOG_WITH_STREAM(MediaQueries, stream << "FrameView " << this << " snapshotting size " << ScrollView::layoutSize() << " for media queries");
1333 m_frameFlatteningViewSizeForMediaQuery = ScrollView::layoutSize();
1335 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1336 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1337 if (!root || !root->needsLayout())
1341 TraceScope tracingScope(LayoutStart, LayoutEnd);
1344 if (updateFixedPositionLayoutRect())
1345 allowSubtree = false;
1348 m_layoutTimer.stop();
1349 m_delayedLayout = false;
1350 m_setNeedsLayoutWasDeferred = false;
1352 // we shouldn't enter layout() while painting
1353 ASSERT(!isPainting());
1357 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(frame());
1358 AnimationUpdateBlock animationUpdateBlock(&frame().animation());
1360 if (!allowSubtree && m_layoutRoot)
1361 convertSubtreeLayoutToFullLayout();
1363 ASSERT(frame().view() == this);
1364 ASSERT(frame().document());
1366 Document& document = *frame().document();
1367 ASSERT(document.pageCacheState() == Document::NotInPageCache);
1370 SetForScope<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1372 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1373 // This is a new top-level layout. If there are any remaining tasks from the previous
1374 // layout, finish them now.
1375 SetForScope<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1376 performPostLayoutTasks();
1379 m_layoutPhase = InPreLayoutStyleUpdate;
1381 // Viewport-dependent media queries may cause us to need completely different style information.
1382 auto* styleResolver = document.styleScope().resolverIfExists();
1383 if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) {
1384 LOG(Layout, " hasMediaQueriesAffectedByViewportChange, enqueueing style recalc");
1385 document.styleScope().didChangeStyleSheetEnvironment();
1386 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1387 InspectorInstrumentation::mediaQueryResultChanged(document);
1389 document.evaluateMediaQueryList();
1390 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1391 // take care of that now.
1392 applyPaginationToViewport();
1393 // Always ensure our style info is up-to-date. This can happen in situations where
1394 // the layout beats any sort of style recalc update that needs to occur.
1395 document.updateStyleIfNeeded();
1396 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1397 // so there's no point to continuing to layout
1401 // Close block here so we can set up the font cache purge preventer, which we will still
1402 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1403 // The next block sets m_layoutSchedulingEnabled back to false once again.
1406 m_layoutPhase = InPreLayout;
1408 RenderLayer* layer = nullptr;
1409 bool subtree = false;
1410 RenderElement* root = nullptr;
1412 ++m_nestedLayoutCount;
1415 SetForScope<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1417 autoSizeIfEnabled();
1419 root = m_layoutRoot ? m_layoutRoot : document.renderView();
1422 subtree = m_layoutRoot;
1424 if (!m_layoutRoot) {
1425 auto* body = document.bodyOrFrameset();
1426 if (body && body->renderer()) {
1427 if (is<HTMLFrameSetElement>(*body) && !frameFlatteningEnabled()) {
1428 body->renderer()->setChildNeedsLayout();
1429 } else if (is<HTMLBodyElement>(*body)) {
1430 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport())
1431 body->renderer()->setChildNeedsLayout();
1436 if (m_firstLayout && !frame().ownerElement())
1437 LOG(Layout, "FrameView %p elapsed time before first layout: %.3fs\n", this, document.timeSinceDocumentCreation().value());
1441 m_needsFullRepaint = !subtree && (m_firstLayout || downcast<RenderView>(*root).printing());
1444 ScrollbarMode hMode;
1445 ScrollbarMode vMode;
1446 calculateScrollbarModesForLayout(hMode, vMode);
1448 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1449 if (m_firstLayout) {
1450 setScrollbarsSuppressed(true);
1452 m_firstLayout = false;
1453 m_firstLayoutCallbackPending = true;
1454 m_lastViewportSize = sizeForResizeEvent();
1455 m_lastZoomFactor = root->style().zoom();
1457 // Set the initial vMode to AlwaysOn if we're auto.
1458 if (vMode == ScrollbarAuto)
1459 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1460 // Set the initial hMode to AlwaysOff if we're auto.
1461 if (hMode == ScrollbarAuto)
1462 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1463 Page* page = frame().page();
1464 if (page && page->expectsWheelEventTriggers())
1465 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
1466 setScrollbarModes(hMode, vMode);
1467 setScrollbarsSuppressed(false, true);
1469 setScrollbarModes(hMode, vMode);
1472 LayoutSize oldSize = m_size;
1473 m_size = layoutSize();
1475 if (oldSize != m_size) {
1476 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());
1477 m_needsFullRepaint = true;
1478 if (!m_firstLayout) {
1479 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : nullptr;
1480 auto* body = document.bodyOrFrameset();
1481 RenderBox* bodyRenderer = rootRenderer && body ? body->renderBox() : nullptr;
1482 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1483 bodyRenderer->setChildNeedsLayout();
1484 else if (rootRenderer && rootRenderer->stretchesToViewport())
1485 rootRenderer->setChildNeedsLayout();
1489 m_layoutPhase = InPreLayout;
1492 layer = root->enclosingLayer();
1493 SubtreeLayoutStateMaintainer subtreeLayoutStateMaintainer(m_layoutRoot);
1495 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1497 ASSERT(m_layoutPhase == InPreLayout);
1498 m_layoutPhase = InRenderTreeLayout;
1500 forceLayoutParentViewIfNeeded();
1502 ASSERT(m_layoutPhase == InRenderTreeLayout);
1504 RenderTreeNeedsLayoutChecker checker(*root);
1508 #if ENABLE(TEXT_AUTOSIZING)
1509 if (frame().settings().textAutosizingEnabled() && !root->view().printing()) {
1510 float minimumZoomFontSize = frame().settings().minimumZoomFontSize();
1511 float textAutosizingWidth = frame().page() ? frame().page()->textAutosizingWidth() : 0;
1512 if (int overrideWidth = frame().settings().textAutosizingWindowSizeOverride().width())
1513 textAutosizingWidth = overrideWidth;
1515 LOG(TextAutosizing, "Text Autosizing: minimumZoomFontSize=%.2f textAutosizingWidth=%.2f", minimumZoomFontSize, textAutosizingWidth);
1517 if (minimumZoomFontSize && textAutosizingWidth) {
1518 root->adjustComputedFontSizesOnBlocks(minimumZoomFontSize, textAutosizingWidth);
1519 if (root->needsLayout())
1525 ASSERT(m_layoutPhase == InRenderTreeLayout);
1526 m_layoutRoot = nullptr;
1527 // Close block here to end the scope of changeSchedulingEnabled and SubtreeLayoutStateMaintainer.
1530 m_layoutPhase = InViewSizeAdjust;
1532 bool neededFullRepaint = m_needsFullRepaint;
1534 if (!subtree && !downcast<RenderView>(*root).printing()) {
1536 // FIXME: Firing media query callbacks synchronously on nested frames could produced a detached FrameView here by
1537 // navigating away from the current document (see webkit.org/b/173329).
1542 m_layoutPhase = InPostLayout;
1544 m_needsFullRepaint = neededFullRepaint;
1546 // Now update the positions of all layers.
1547 if (m_needsFullRepaint)
1548 root->view().repaintRootContents();
1550 root->view().releaseProtectedRenderWidgets();
1552 ASSERT(!root->needsLayout());
1554 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1556 updateCompositingLayersAfterLayout();
1558 m_layoutPhase = InPostLayerPositionsUpdatedAfterLayout;
1562 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK)
1563 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1564 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1567 #if ENABLE(DASHBOARD_SUPPORT)
1568 updateAnnotatedRegions();
1571 #if ENABLE(IOS_TOUCH_EVENTS)
1572 document.setTouchEventRegionsNeedUpdate();
1575 updateCanBlitOnScrollRecursively();
1577 handleDeferredScrollUpdateAfterContentSizeChange();
1579 handleDeferredScrollbarsUpdateAfterDirectionChange();
1581 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1582 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1584 frame().document()->markers().invalidateRectsForAllMarkers();
1586 if (!m_postLayoutTasksTimer.isActive()) {
1587 if (!m_inSynchronousPostLayout) {
1588 if (inChildFrameLayoutWithFrameFlattening)
1589 updateWidgetPositions();
1591 SetForScope<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1592 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1596 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1597 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1598 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1599 // can make us need to update again, and we can get stuck in a nasty cycle unless
1600 // we call it through the timer here.
1601 m_postLayoutTasksTimer.startOneShot(0_s);
1607 InspectorInstrumentation::didLayout(cookie, *root);
1608 DebugPageOverlays::didLayout(frame());
1610 --m_nestedLayoutCount;
1613 bool FrameView::shouldDeferScrollUpdateAfterContentSizeChange()
1615 return (m_layoutPhase < InPostLayout) && (m_layoutPhase != OutsideLayout);
1618 RenderBox* FrameView::embeddedContentBox() const
1620 RenderView* renderView = this->renderView();
1624 RenderObject* firstChild = renderView->firstChild();
1626 // Curently only embedded SVG documents participate in the size-negotiation logic.
1627 if (is<RenderSVGRoot>(firstChild))
1628 return downcast<RenderSVGRoot>(firstChild);
1633 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1635 if (!m_embeddedObjectsToUpdate)
1636 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1638 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1639 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
1640 // Tell the DOM element that it needs a widget update.
1641 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
1642 if (!pluginElement.needsCheckForSizeChange())
1643 pluginElement.setNeedsWidgetUpdate(true);
1646 m_embeddedObjectsToUpdate->add(&embeddedObject);
1649 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1651 if (!m_embeddedObjectsToUpdate)
1654 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1657 void FrameView::setMediaType(const String& mediaType)
1659 m_mediaType = mediaType;
1662 String FrameView::mediaType() const
1664 // See if we have an override type.
1665 String overrideType = frame().loader().client().overrideMediaType();
1666 InspectorInstrumentation::applyEmulatedMedia(frame(), overrideType);
1667 if (!overrideType.isNull())
1668 return overrideType;
1672 void FrameView::adjustMediaTypeForPrinting(bool printing)
1675 if (m_mediaTypeWhenNotPrinting.isNull())
1676 m_mediaTypeWhenNotPrinting = mediaType();
1677 setMediaType("print");
1679 if (!m_mediaTypeWhenNotPrinting.isNull())
1680 setMediaType(m_mediaTypeWhenNotPrinting);
1681 m_mediaTypeWhenNotPrinting = String();
1685 bool FrameView::useSlowRepaints(bool considerOverlap) const
1687 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1689 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1690 // m_contentIsOpaque, so don't take the fast path for composited layers
1691 // if they are a platform widget in order to get painting correctness
1692 // for transparent layers. See the comment in WidgetMac::paint.
1693 if (usesCompositedScrolling() && !platformWidget())
1696 bool isOverlapped = m_isOverlapped && considerOverlap;
1698 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1701 if (FrameView* parentView = parentFrameView())
1702 return parentView->useSlowRepaints(considerOverlap);
1707 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1709 return useSlowRepaints(false);
1712 void FrameView::updateCanBlitOnScrollRecursively()
1714 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
1715 if (FrameView* view = frame->view())
1716 view->setCanBlitOnScroll(!view->useSlowRepaints());
1720 bool FrameView::usesCompositedScrolling() const
1722 RenderView* renderView = this->renderView();
1723 if (renderView && renderView->isComposited()) {
1724 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1725 if (layer && layer->drawsContent())
1732 bool FrameView::usesAsyncScrolling() const
1734 #if ENABLE(ASYNC_SCROLLING)
1735 if (Page* page = frame().page()) {
1736 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1737 return scrollingCoordinator->coordinatesScrollingForFrameView(*this);
1743 bool FrameView::usesMockScrollAnimator() const
1745 return Settings::usesMockScrollAnimator();
1748 void FrameView::logMockScrollAnimatorMessage(const String& message) const
1750 Document* document = frame().document();
1753 StringBuilder builder;
1754 if (frame().isMainFrame())
1755 builder.appendLiteral("Main");
1756 builder.appendLiteral("FrameView: ");
1757 builder.append(message);
1758 document->addConsoleMessage(MessageSource::Other, MessageLevel::Debug, builder.toString());
1761 void FrameView::setCannotBlitToWindow()
1763 m_cannotBlitToWindow = true;
1764 updateCanBlitOnScrollRecursively();
1767 void FrameView::addSlowRepaintObject(RenderElement* o)
1769 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1771 if (!m_slowRepaintObjects)
1772 m_slowRepaintObjects = std::make_unique<HashSet<const RenderElement*>>();
1774 m_slowRepaintObjects->add(o);
1776 if (!hadSlowRepaintObjects) {
1777 updateCanBlitOnScrollRecursively();
1779 if (Page* page = frame().page()) {
1780 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1781 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(*this);
1786 void FrameView::removeSlowRepaintObject(RenderElement* o)
1788 if (!m_slowRepaintObjects)
1791 m_slowRepaintObjects->remove(o);
1792 if (m_slowRepaintObjects->isEmpty()) {
1793 m_slowRepaintObjects = nullptr;
1794 updateCanBlitOnScrollRecursively();
1796 if (Page* page = frame().page()) {
1797 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1798 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(*this);
1803 void FrameView::addViewportConstrainedObject(RenderElement* object)
1805 if (!m_viewportConstrainedObjects)
1806 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1808 if (!m_viewportConstrainedObjects->contains(object)) {
1809 m_viewportConstrainedObjects->add(object);
1810 if (platformWidget())
1811 updateCanBlitOnScrollRecursively();
1813 if (Page* page = frame().page()) {
1814 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1815 scrollingCoordinator->frameViewFixedObjectsDidChange(*this);
1820 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1822 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1823 if (Page* page = frame().page()) {
1824 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1825 scrollingCoordinator->frameViewFixedObjectsDidChange(*this);
1828 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1829 // why isn't the same check being made here?
1830 updateCanBlitOnScrollRecursively();
1834 LayoutRect FrameView::computeUpdatedLayoutViewportRect(const LayoutRect& layoutViewport, const LayoutRect& documentRect, const LayoutSize& unobscuredContentSize, const LayoutRect& unobscuredContentRect, const LayoutSize& baseLayoutViewportSize, const LayoutPoint& stableLayoutViewportOriginMin, const LayoutPoint& stableLayoutViewportOriginMax, LayoutViewportConstraint constraint)
1836 LayoutRect layoutViewportRect = layoutViewport;
1838 // The layout viewport is never smaller than baseLayoutViewportSize, and never be smaller than the unobscuredContentRect.
1839 LayoutSize constrainedSize = baseLayoutViewportSize;
1840 layoutViewportRect.setSize(constrainedSize.expandedTo(unobscuredContentSize));
1842 LayoutPoint layoutViewportOrigin = computeLayoutViewportOrigin(unobscuredContentRect, stableLayoutViewportOriginMin, stableLayoutViewportOriginMax, layoutViewportRect, StickToViewportBounds);
1844 // FIXME: Is this equivalent to calling computeLayoutViewportOrigin() with StickToDocumentBounds?
1845 if (constraint == LayoutViewportConstraint::ConstrainedToDocumentRect) {
1846 // The max stable layout viewport origin really depends on the size of the layout viewport itself, so we need to adjust the location of the layout viewport one final time to make sure it does not end up out of bounds of the document.
1847 // Without this adjustment (and with using the non-constrained unobscuredContentRect's size as the size of the layout viewport) the layout viewport can be pushed past the bounds of the document during rubber-banding, and cannot be pushed
1848 // back in until the user scrolls back in the other direction.
1849 layoutViewportOrigin.setX(clampTo<float>(layoutViewportOrigin.x(), 0, documentRect.width() - layoutViewportRect.width()));
1850 layoutViewportOrigin.setY(clampTo<float>(layoutViewportOrigin.y(), 0, documentRect.height() - layoutViewportRect.height()));
1852 layoutViewportRect.setLocation(layoutViewportOrigin);
1854 return layoutViewportRect;
1857 // visualViewport and layoutViewport are both in content coordinates (unzoomed).
1858 LayoutPoint FrameView::computeLayoutViewportOrigin(const LayoutRect& visualViewport, const LayoutPoint& stableLayoutViewportOriginMin, const LayoutPoint& stableLayoutViewportOriginMax, const LayoutRect& layoutViewport, ScrollBehaviorForFixedElements fixedBehavior)
1860 LayoutPoint layoutViewportOrigin = layoutViewport.location();
1861 bool allowRubberBanding = fixedBehavior == StickToViewportBounds;
1863 if (visualViewport.width() > layoutViewport.width()) {
1864 layoutViewportOrigin.setX(visualViewport.x());
1865 if (!allowRubberBanding) {
1866 if (layoutViewportOrigin.x() < stableLayoutViewportOriginMin.x())
1867 layoutViewportOrigin.setX(stableLayoutViewportOriginMin.x());
1868 else if (layoutViewportOrigin.x() > stableLayoutViewportOriginMax.x())
1869 layoutViewportOrigin.setX(stableLayoutViewportOriginMax.x());
1872 bool rubberbandingAtLeft = allowRubberBanding && visualViewport.x() < stableLayoutViewportOriginMin.x();
1873 bool rubberbandingAtRight = allowRubberBanding && (visualViewport.maxX() - layoutViewport.width()) > stableLayoutViewportOriginMax.x();
1875 if (visualViewport.x() < layoutViewport.x() || rubberbandingAtLeft)
1876 layoutViewportOrigin.setX(visualViewport.x());
1878 if (visualViewport.maxX() > layoutViewport.maxX() || rubberbandingAtRight)
1879 layoutViewportOrigin.setX(visualViewport.maxX() - layoutViewport.width());
1881 if (!rubberbandingAtLeft && layoutViewportOrigin.x() < stableLayoutViewportOriginMin.x())
1882 layoutViewportOrigin.setX(stableLayoutViewportOriginMin.x());
1884 if (!rubberbandingAtRight && layoutViewportOrigin.x() > stableLayoutViewportOriginMax.x())
1885 layoutViewportOrigin.setX(stableLayoutViewportOriginMax.x());
1888 if (visualViewport.height() > layoutViewport.height()) {
1889 layoutViewportOrigin.setY(visualViewport.y());
1890 if (!allowRubberBanding) {
1891 if (layoutViewportOrigin.y() < stableLayoutViewportOriginMin.y())
1892 layoutViewportOrigin.setY(stableLayoutViewportOriginMin.y());
1893 else if (layoutViewportOrigin.y() > stableLayoutViewportOriginMax.y())
1894 layoutViewportOrigin.setY(stableLayoutViewportOriginMax.y());
1897 bool rubberbandingAtTop = allowRubberBanding && visualViewport.y() < stableLayoutViewportOriginMin.y();
1898 bool rubberbandingAtBottom = allowRubberBanding && (visualViewport.maxY() - layoutViewport.height()) > stableLayoutViewportOriginMax.y();
1900 if (visualViewport.y() < layoutViewport.y() || rubberbandingAtTop)
1901 layoutViewportOrigin.setY(visualViewport.y());
1903 if (visualViewport.maxY() > layoutViewport.maxY() || rubberbandingAtBottom)
1904 layoutViewportOrigin.setY(visualViewport.maxY() - layoutViewport.height());
1906 if (!rubberbandingAtTop && layoutViewportOrigin.y() < stableLayoutViewportOriginMin.y())
1907 layoutViewportOrigin.setY(stableLayoutViewportOriginMin.y());
1909 if (!rubberbandingAtBottom && layoutViewportOrigin.y() > stableLayoutViewportOriginMax.y())
1910 layoutViewportOrigin.setY(stableLayoutViewportOriginMax.y());
1913 return layoutViewportOrigin;
1916 void FrameView::setBaseLayoutViewportOrigin(LayoutPoint origin, TriggerLayoutOrNot layoutTriggering)
1918 ASSERT(frame().settings().visualViewportEnabled());
1920 if (origin == m_layoutViewportOrigin)
1923 m_layoutViewportOrigin = origin;
1924 if (layoutTriggering == TriggerLayoutOrNot::Yes)
1925 setViewportConstrainedObjectsNeedLayout();
1927 if (TiledBacking* tiledBacking = this->tiledBacking()) {
1928 FloatRect layoutViewport = layoutViewportRect();
1929 layoutViewport.moveBy(unscaledScrollOrigin()); // tiledBacking deals in top-left relative coordinates.
1930 tiledBacking->setLayoutViewportRect(layoutViewport);
1934 void FrameView::setLayoutViewportOverrideRect(std::optional<LayoutRect> rect, TriggerLayoutOrNot layoutTriggering)
1936 if (rect == m_layoutViewportOverrideRect)
1939 LayoutRect oldRect = layoutViewportRect();
1940 m_layoutViewportOverrideRect = rect;
1942 // Triggering layout on height changes is necessary to make bottom-fixed elements behave correctly.
1943 if (oldRect.height() != layoutViewportRect().height())
1944 layoutTriggering = TriggerLayoutOrNot::Yes;
1946 LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " setLayoutViewportOverrideRect() - changing override layout viewport from " << oldRect << " to " << m_layoutViewportOverrideRect.value_or(LayoutRect()) << " layoutTriggering " << (layoutTriggering == TriggerLayoutOrNot::Yes ? "yes" : "no"));
1948 if (oldRect != layoutViewportRect() && layoutTriggering == TriggerLayoutOrNot::Yes)
1949 setViewportConstrainedObjectsNeedLayout();
1952 LayoutSize FrameView::baseLayoutViewportSize() const
1954 return renderView() ? renderView()->size() : size();
1957 void FrameView::updateLayoutViewport()
1959 if (!frame().settings().visualViewportEnabled())
1962 // Don't update the layout viewport if we're in the middle of adjusting scrollbars. We'll get another call
1963 // as a post-layout task.
1964 if (m_layoutPhase == InViewSizeAdjust)
1967 LayoutRect layoutViewport = layoutViewportRect();
1969 LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " updateLayoutViewport() totalContentSize " << totalContentsSize() << " unscaledDocumentRect " << (renderView() ? renderView()->unscaledDocumentRect() : IntRect()) << " header height " << headerHeight() << " footer height " << footerHeight() << " fixed behavior " << scrollBehaviorForFixedElements());
1970 LOG_WITH_STREAM(Scrolling, stream << "layoutViewport: " << layoutViewport);
1971 LOG_WITH_STREAM(Scrolling, stream << "visualViewport: " << visualViewportRect());
1972 LOG_WITH_STREAM(Scrolling, stream << "stable origins: min: " << minStableLayoutViewportOrigin() << " max: "<< maxStableLayoutViewportOrigin());
1974 if (m_layoutViewportOverrideRect) {
1975 if (m_inProgrammaticScroll) {
1976 LayoutPoint newOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport, StickToDocumentBounds);
1977 setLayoutViewportOverrideRect(LayoutRect(newOrigin, m_layoutViewportOverrideRect.value().size()));
1982 LayoutPoint newLayoutViewportOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport, scrollBehaviorForFixedElements());
1983 if (newLayoutViewportOrigin != m_layoutViewportOrigin) {
1984 setBaseLayoutViewportOrigin(newLayoutViewportOrigin);
1985 LOG_WITH_STREAM(Scrolling, stream << "layoutViewport changed to " << layoutViewportRect());
1989 LayoutPoint FrameView::minStableLayoutViewportOrigin() const
1991 return unscaledMinimumScrollPosition();
1994 LayoutPoint FrameView::maxStableLayoutViewportOrigin() const
1996 LayoutPoint maxPosition = unscaledMaximumScrollPosition();
1997 maxPosition = (maxPosition - LayoutSize(0, headerHeight() + footerHeight())).expandedTo({ });
2001 IntPoint FrameView::unscaledScrollOrigin() const
2003 if (RenderView* renderView = this->renderView())
2004 return -renderView->unscaledDocumentRect().location(); // Akin to code in adjustViewSize().
2009 LayoutRect FrameView::layoutViewportRect() const
2011 if (m_layoutViewportOverrideRect)
2012 return m_layoutViewportOverrideRect.value();
2014 // Size of initial containing block, anchored at scroll position, in document coordinates (unchanged by scale factor).
2015 return LayoutRect(m_layoutViewportOrigin, baseLayoutViewportSize());
2018 // visibleContentRect is in the bounds of the scroll view content. That consists of an
2019 // optional header, the document, and an optional footer. Only the document is scaled,
2020 // so we have to compute the visible part of the document in unscaled document coordinates.
2021 // On iOS, pageScaleFactor is always 1 here, and we never have headers and footers.
2022 LayoutRect FrameView::visibleDocumentRect(const FloatRect& visibleContentRect, float headerHeight, float footerHeight, const FloatSize& totalContentsSize, float pageScaleFactor)
2024 float contentsHeight = totalContentsSize.height() - headerHeight - footerHeight;
2026 float rubberBandTop = std::min<float>(visibleContentRect.y(), 0);
2027 float visibleScaledDocumentTop = std::max<float>(visibleContentRect.y() - headerHeight, 0) + rubberBandTop;
2029 float rubberBandBottom = std::min<float>((totalContentsSize.height() - visibleContentRect.y()) - visibleContentRect.height(), 0);
2030 float visibleScaledDocumentBottom = std::min<float>(visibleContentRect.maxY() - headerHeight, contentsHeight) - rubberBandBottom;
2032 FloatRect visibleDocumentRect = visibleContentRect;
2033 visibleDocumentRect.setY(visibleScaledDocumentTop);
2034 visibleDocumentRect.setHeight(std::max<float>(visibleScaledDocumentBottom - visibleScaledDocumentTop, 0));
2035 visibleDocumentRect.scale(1 / pageScaleFactor);
2037 return LayoutRect(visibleDocumentRect);
2040 LayoutRect FrameView::visualViewportRect() const
2042 FloatRect visibleContentRect = this->visibleContentRect(LegacyIOSDocumentVisibleRect);
2043 return visibleDocumentRect(visibleContentRect, headerHeight(), footerHeight(), totalContentsSize(), frameScaleFactor());
2046 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
2048 ASSERT(!frame().settings().visualViewportEnabled());
2051 if (useCustomFixedPositionLayoutRect())
2052 return customFixedPositionLayoutRect();
2054 LayoutRect viewportRect = visibleContentRect();
2056 viewportRect.setLocation(scrollPositionForFixedPosition());
2057 return viewportRect;
2060 LayoutRect FrameView::rectForFixedPositionLayout() const
2062 if (frame().settings().visualViewportEnabled())
2063 return layoutViewportRect();
2065 return viewportConstrainedVisibleContentRect();
2068 float FrameView::frameScaleFactor() const
2070 return frame().frameScaleFactor();
2073 LayoutPoint FrameView::scrollPositionForFixedPosition() const
2075 if (frame().settings().visualViewportEnabled())
2076 return layoutViewportRect().location();
2078 return scrollPositionForFixedPosition(visibleContentRect(), totalContentsSize(), scrollPosition(), scrollOrigin(), frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements(), headerHeight(), footerHeight());
2081 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)
2083 LayoutPoint position;
2084 if (behaviorForFixed == StickToDocumentBounds)
2085 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
2087 position = scrollPosition;
2088 position.setY(position.y() - headerHeight);
2091 LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
2093 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
2094 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
2096 return LayoutPoint(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
2099 float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset)
2101 if (!topContentInset)
2104 // The insetClipLayer should not move for negative scroll values.
2105 float scrollY = std::max<float>(0, scrollPosition.y());
2107 if (scrollY >= topContentInset)
2110 return topContentInset - scrollY;
2113 float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset)
2115 if (!topContentInset)
2118 float scrollY = std::max<float>(0, scrollPosition.y());
2120 if (scrollY >= topContentInset)
2121 return topContentInset;
2126 float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight)
2128 return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight;
2131 FloatPoint FrameView::positionForRootContentLayer(const FloatPoint& scrollPosition, const FloatPoint& scrollOrigin, float topContentInset, float headerHeight)
2133 return FloatPoint(0, yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight) - toFloatSize(scrollOrigin);
2136 FloatPoint FrameView::positionForRootContentLayer() const
2138 return positionForRootContentLayer(scrollPosition(), scrollOrigin(), topContentInset(), headerHeight());
2142 LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
2144 if (fixedElementsLayoutRelativeToFrame)
2145 return visibleContentRect;
2147 if (totalContentsSize.isEmpty())
2148 return visibleContentRect;
2150 // We impose an lower limit on the size (so an upper limit on the scale) of
2151 // the rect used to position fixed objects so that they don't crowd into the
2152 // center of the screen at larger scales.
2153 const LayoutUnit maxContentWidthForZoomThreshold = LayoutUnit::fromPixel(1024);
2154 float zoomedOutScale = frameScaleFactor * visibleContentRect.width() / std::min(maxContentWidthForZoomThreshold, totalContentsSize.width());
2155 float constraintThresholdScale = 1.5 * zoomedOutScale;
2156 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
2158 LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
2160 if (frameScaleFactor > constraintThresholdScale) {
2161 FloatRect contentRect(FloatPoint(), totalContentsSize);
2162 FloatRect viewportRect = visibleContentRect;
2164 // Scale the rect up from a point that is relative to its position in the viewport.
2165 FloatSize sizeDelta = contentRect.size() - viewportRect.size();
2167 FloatPoint scaleOrigin;
2168 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
2169 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
2171 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
2172 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
2173 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
2175 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
2178 if (scrollBehavior == StickToDocumentBounds) {
2179 LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
2180 viewportConstrainedObjectsRect.intersect(documentBounds);
2183 return viewportConstrainedObjectsRect;
2186 LayoutRect FrameView::viewportConstrainedObjectsRect() const
2188 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
2192 ScrollPosition FrameView::minimumScrollPosition() const
2194 ScrollPosition minimumPosition = ScrollView::minimumScrollPosition();
2196 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
2197 minimumPosition.setY(maximumScrollPosition().y());
2199 return minimumPosition;
2202 ScrollPosition FrameView::maximumScrollPosition() const
2204 ScrollPosition maximumPosition = ScrollView::maximumScrollPosition();
2206 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
2207 maximumPosition.setY(minimumScrollPosition().y());
2209 return maximumPosition;
2212 ScrollPosition FrameView::unscaledMinimumScrollPosition() const
2214 if (RenderView* renderView = this->renderView()) {
2215 IntRect unscaledDocumentRect = renderView->unscaledDocumentRect();
2216 ScrollPosition minimumPosition = unscaledDocumentRect.location();
2218 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
2219 minimumPosition.setY(unscaledMaximumScrollPosition().y());
2221 return minimumPosition;
2224 return minimumScrollPosition();
2227 ScrollPosition FrameView::unscaledMaximumScrollPosition() const
2229 if (RenderView* renderView = this->renderView()) {
2230 IntRect unscaledDocumentRect = renderView->unscaledDocumentRect();
2231 unscaledDocumentRect.expand(0, headerHeight() + footerHeight());
2232 IntSize visibleSize = this->visibleSize();
2234 // FIXME: visibleSize() is the unscaled size on macOS, but the scaled size on iOS. This should be consistent. webkit.org/b/174648.
2235 visibleSize.scale(visibleContentScaleFactor());
2237 ScrollPosition maximumPosition = ScrollPosition(unscaledDocumentRect.maxXMaxYCorner() - visibleSize).expandedTo({ 0, 0 });
2238 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
2239 maximumPosition.setY(unscaledMinimumScrollPosition().y());
2241 return maximumPosition;
2244 return maximumScrollPosition();
2247 void FrameView::viewportContentsChanged()
2249 if (!frame().view()) {
2250 // The frame is being destroyed.
2254 if (auto* page = frame().page())
2255 page->updateValidationBubbleStateIfNeeded();
2257 // When the viewport contents changes (scroll, resize, style recalc, layout, ...),
2258 // check if we should resume animated images or unthrottle DOM timers.
2259 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) {
2260 frameView.resumeVisibleImageAnimations(visibleRect);
2261 frameView.updateScriptedAnimationsAndTimersThrottlingState(visibleRect);
2263 if (auto* renderView = frameView.frame().contentRenderer())
2264 renderView->updateVisibleViewportRect(visibleRect);
2268 bool FrameView::fixedElementsLayoutRelativeToFrame() const
2270 return frame().settings().fixedElementsLayoutRelativeToFrame();
2273 IntPoint FrameView::lastKnownMousePosition() const
2275 return frame().eventHandler().lastKnownMousePosition();
2278 bool FrameView::isHandlingWheelEvent() const
2280 return frame().eventHandler().isHandlingWheelEvent();
2283 bool FrameView::shouldSetCursor() const
2285 Page* page = frame().page();
2286 return page && page->isVisible() && page->focusController().isActive();
2289 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
2291 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
2292 frame().page()->chrome().scroll(scrollDelta, rectToScroll, clipRect);
2296 bool isCompositedContentLayer = usesCompositedScrolling();
2298 // Get the rects of the fixed objects visible in the rectToScroll
2299 Region regionToUpdate;
2300 for (auto& renderer : *m_viewportConstrainedObjects) {
2301 if (!renderer->style().hasViewportConstrainedPosition())
2303 if (renderer->isComposited())
2306 // Fixed items should always have layers.
2307 ASSERT(renderer->hasLayer());
2308 RenderLayer* layer = downcast<RenderBoxModelObject>(*renderer).layer();
2310 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
2311 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
2312 // Don't invalidate for invisible fixed layers.
2316 if (layer->hasAncestorWithFilterOutsets()) {
2317 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
2318 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
2322 // FIXME: use pixel snapping instead of enclosing when ScrollView has finished transitioning from IntRect to Float/LayoutRect.
2323 IntRect updateRect = enclosingIntRect(layer->repaintRectIncludingNonCompositingDescendants());
2324 updateRect = contentsToRootView(updateRect);
2325 if (!isCompositedContentLayer)
2326 updateRect.intersect(rectToScroll);
2327 if (!updateRect.isEmpty())
2328 regionToUpdate.unite(updateRect);
2332 frame().page()->chrome().scroll(scrollDelta, rectToScroll, clipRect);
2334 // 2) update the area of fixed objects that has been invalidated
2335 for (auto& updateRect : regionToUpdate.rects()) {
2336 IntRect scrolledRect = updateRect;
2337 scrolledRect.move(scrollDelta);
2338 updateRect.unite(scrolledRect);
2339 if (isCompositedContentLayer) {
2340 updateRect = rootViewToContents(updateRect);
2341 ASSERT(renderView());
2342 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
2345 updateRect.intersect(rectToScroll);
2346 frame().page()->chrome().invalidateContentsAndRootView(updateRect);
2352 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
2354 repaintSlowRepaintObjects();
2356 if (!usesCompositedScrolling() && isEnclosedInCompositingLayer()) {
2357 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
2358 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), frameRenderer->borderTop() + frameRenderer->paddingTop(),
2359 visibleWidth(), visibleHeight());
2360 frameRenderer->repaintRectangle(rect);
2365 ScrollView::scrollContentsSlowPath(updateRect);
2368 void FrameView::repaintSlowRepaintObjects()
2370 if (!m_slowRepaintObjects)
2373 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
2374 // repaint them after scrolling.
2375 for (auto& renderer : *m_slowRepaintObjects)
2376 renderer->repaintSlowRepaintObject();
2379 // Note that this gets called at painting time.
2380 void FrameView::setIsOverlapped(bool isOverlapped)
2382 if (isOverlapped == m_isOverlapped)
2385 m_isOverlapped = isOverlapped;
2386 updateCanBlitOnScrollRecursively();
2389 void FrameView::setContentIsOpaque(bool contentIsOpaque)
2391 if (contentIsOpaque == m_contentIsOpaque)
2394 m_contentIsOpaque = contentIsOpaque;
2395 updateCanBlitOnScrollRecursively();
2398 void FrameView::restoreScrollbar()
2400 setScrollbarsSuppressed(false);
2403 bool FrameView::scrollToFragment(const URL& url)
2405 // If our URL has no ref, then we have no place we need to jump to.
2406 // OTOH If CSS target was set previously, we want to set it to 0, recalc
2407 // and possibly repaint because :target pseudo class may have been
2408 // set (see bug 11321).
2409 if (!url.hasFragmentIdentifier()) {
2410 frame().document()->setCSSTarget(nullptr);
2414 String fragmentIdentifier = url.fragmentIdentifier();
2415 if (scrollToAnchor(fragmentIdentifier))
2418 // Try again after decoding the ref, based on the document's encoding.
2419 if (TextResourceDecoder* decoder = frame().document()->decoder())
2420 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
2425 bool FrameView::scrollToAnchor(const String& name)
2427 ASSERT(frame().document());
2428 auto& document = *frame().document();
2430 if (!document.haveStylesheetsLoaded()) {
2431 document.setGotoAnchorNeededAfterStylesheetsLoad(true);
2435 document.setGotoAnchorNeededAfterStylesheetsLoad(false);
2437 Element* anchorElement = document.findAnchor(name);
2439 // Setting to null will clear the current target.
2440 document.setCSSTarget(anchorElement);
2442 if (is<SVGDocument>(document)) {
2443 if (auto* rootElement = SVGDocument::rootElement(document)) {
2444 rootElement->scrollToAnchor(name, anchorElement);
2450 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2451 if (!anchorElement && !(name.isEmpty() || equalLettersIgnoringASCIICase(name, "top")))
2454 ContainerNode* scrollPositionAnchor = anchorElement;
2455 if (!scrollPositionAnchor)
2456 scrollPositionAnchor = frame().document();
2457 maintainScrollPositionAtAnchor(scrollPositionAnchor);
2459 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
2460 if (anchorElement) {
2461 if (anchorElement->isFocusable())
2462 document.setFocusedElement(anchorElement);
2464 document.setFocusedElement(nullptr);
2465 document.setFocusNavigationStartingNode(anchorElement);
2472 void FrameView::maintainScrollPositionAtAnchor(ContainerNode* anchorNode)
2474 m_maintainScrollPositionAnchor = anchorNode;
2475 if (!m_maintainScrollPositionAnchor)
2478 // We need to update the layout before scrolling, otherwise we could
2479 // really mess things up if an anchor scroll comes at a bad moment.
2480 frame().document()->updateStyleIfNeeded();
2481 // Only do a layout if changes have occurred that make it necessary.
2482 RenderView* renderView = this->renderView();
2483 if (renderView && renderView->needsLayout())
2489 void FrameView::scrollElementToRect(const Element& element, const IntRect& rect)
2491 frame().document()->updateLayoutIgnorePendingStylesheets();
2494 if (RenderElement* renderer = element.renderer())
2495 bounds = renderer->absoluteAnchorRect();
2496 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
2497 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
2498 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
2501 void FrameView::setScrollPosition(const ScrollPosition& scrollPosition)
2503 SetForScope<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
2504 m_maintainScrollPositionAnchor = nullptr;
2505 Page* page = frame().page();
2506 if (page && page->expectsWheelEventTriggers())
2507 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
2508 ScrollView::setScrollPosition(scrollPosition);
2511 void FrameView::contentsResized()
2513 // For non-delegated scrolling, updateTiledBackingAdaptiveSizing() is called via addedOrRemovedScrollbar() which occurs less often.
2514 if (delegatesScrolling())
2515 updateTiledBackingAdaptiveSizing();
2518 void FrameView::delegatesScrollingDidChange()
2520 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
2521 if (hasCompositedContent())
2522 clearBackingStores();
2525 #if USE(COORDINATED_GRAPHICS)
2526 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
2528 bool visibleContentSizeDidChange = false;
2529 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
2530 // When the viewport size changes or the content is scaled, we need to
2531 // reposition the fixed and sticky positioned elements.
2532 setViewportConstrainedObjectsNeedLayout();
2533 visibleContentSizeDidChange = true;
2536 IntPoint oldPosition = scrollPosition();
2537 ScrollView::setFixedVisibleContentRect(visibleContentRect);
2538 IntPoint newPosition = scrollPosition();
2539 if (oldPosition != newPosition) {
2540 updateLayerPositionsAfterScrolling();
2541 if (frame().settings().acceleratedCompositingForFixedPositionEnabled())
2542 updateCompositingLayersAfterScrolling();
2543 scrollAnimator().setCurrentPosition(newPosition);
2544 scrollPositionChanged(oldPosition, newPosition);
2546 if (visibleContentSizeDidChange) {
2547 // Update the scroll-bars to calculate new page-step size.
2548 updateScrollbars(scrollPosition());
2550 didChangeScrollOffset();
2554 void FrameView::setViewportConstrainedObjectsNeedLayout()
2556 if (!hasViewportConstrainedObjects())
2559 for (auto& renderer : *m_viewportConstrainedObjects)
2560 renderer->setNeedsLayout();
2563 void FrameView::didChangeScrollOffset()
2565 frame().mainFrame().pageOverlayController().didScrollFrame(frame());
2566 frame().loader().client().didChangeScrollOffset();
2569 void FrameView::scrollOffsetChangedViaPlatformWidgetImpl(const ScrollOffset& oldOffset, const ScrollOffset& newOffset)
2571 updateLayerPositionsAfterScrolling();
2572 updateCompositingLayersAfterScrolling();
2573 repaintSlowRepaintObjects();
2574 scrollPositionChanged(scrollPositionFromOffset(oldOffset), scrollPositionFromOffset(newOffset));
2577 // These scroll positions are affected by zooming.
2578 void FrameView::scrollPositionChanged(const ScrollPosition& oldPosition, const ScrollPosition& newPosition)
2580 UNUSED_PARAM(oldPosition);
2581 UNUSED_PARAM(newPosition);
2583 Page* page = frame().page();
2584 Seconds throttlingDelay = page ? page->chrome().client().eventThrottlingDelay() : 0_s;
2586 if (throttlingDelay == 0_s) {
2587 m_delayedScrollEventTimer.stop();
2589 } else if (!m_delayedScrollEventTimer.isActive())
2590 m_delayedScrollEventTimer.startOneShot(throttlingDelay);
2592 if (RenderView* renderView = this->renderView()) {
2593 if (renderView->usesCompositing())
2594 renderView->compositor().frameViewDidScroll();
2597 LOG_WITH_STREAM(Scrolling, stream << "FrameView " << this << " scrollPositionChanged from " << oldPosition << " to " << newPosition << " (scale " << frameScaleFactor() << " )");
2598 updateLayoutViewport();
2599 viewportContentsChanged();
2602 void FrameView::applyRecursivelyWithVisibleRect(const WTF::Function<void (FrameView& frameView, const IntRect& visibleRect)>& apply)
2604 IntRect windowClipRect = this->windowClipRect();
2605 auto visibleRect = windowToContents(windowClipRect);
2606 apply(*this, visibleRect);
2608 // Recursive call for subframes. We cache the current FrameView's windowClipRect to avoid recomputing it for every subframe.
2609 SetForScope<IntRect*> windowClipRectCache(m_cachedWindowClipRect, &windowClipRect);
2610 for (Frame* childFrame = frame().tree().firstChild(); childFrame; childFrame = childFrame->tree().nextSibling()) {
2611 if (auto* childView = childFrame->view())
2612 childView->applyRecursivelyWithVisibleRect(apply);
2616 void FrameView::resumeVisibleImageAnimations(const IntRect& visibleRect)
2618 if (visibleRect.isEmpty())
2621 if (auto* renderView = frame().contentRenderer())
2622 renderView->resumePausedImageAnimationsIfNeeded(visibleRect);
2625 void FrameView::updateScriptedAnimationsAndTimersThrottlingState(const IntRect& visibleRect)
2627 if (frame().isMainFrame())
2630 auto* document = frame().document();
2634 // We don't throttle zero-size or display:none frames because those are usually utility frames.
2635 bool shouldThrottle = visibleRect.isEmpty() && !m_size.isEmpty() && frame().ownerRenderer();
2637 if (auto* scriptedAnimationController = document->scriptedAnimationController()) {
2639 scriptedAnimationController->addThrottlingReason(ScriptedAnimationController::ThrottlingReason::OutsideViewport);
2641 scriptedAnimationController->removeThrottlingReason(ScriptedAnimationController::ThrottlingReason::OutsideViewport);
2644 document->setTimerThrottlingEnabled(shouldThrottle);
2648 void FrameView::resumeVisibleImageAnimationsIncludingSubframes()
2650 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) {
2651 frameView.resumeVisibleImageAnimations(visibleRect);
2655 void FrameView::updateLayerPositionsAfterScrolling()
2657 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2658 if (m_layoutPhase == InViewSizeAdjust)
2661 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2662 if (RenderView* renderView = this->renderView()) {
2663 updateWidgetPositions();
2664 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2669 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2671 #if ENABLE(ASYNC_SCROLLING)
2672 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2674 Page* page = frame().page();
2678 if (&page->mainFrame() != m_frame.ptr())
2681 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2682 if (!scrollingCoordinator)
2685 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this))
2688 if (inProgrammaticScroll())
2696 void FrameView::updateCompositingLayersAfterScrolling()
2698 ASSERT(m_layoutPhase >= InPostLayout || m_layoutPhase == OutsideLayout);
2700 if (!shouldUpdateCompositingLayersAfterScrolling())
2703 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2704 if (RenderView* renderView = this->renderView())
2705 renderView->compositor().updateCompositingLayers(CompositingUpdateType::OnScroll);
2709 bool FrameView::isRubberBandInProgress() const
2711 if (scrollbarsSuppressed())
2714 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2715 // ScrollingCoordinator::isRubberBandInProgress().
2716 if (Page* page = frame().page()) {
2717 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2718 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(*this))
2719 return scrollingCoordinator->isRubberBandInProgress();
2723 // If the main thread updates the scroll position for this FrameView, we should return
2724 // ScrollAnimator::isRubberBandInProgress().
2725 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2726 return scrollAnimator->isRubberBandInProgress();
2731 bool FrameView::requestScrollPositionUpdate(const ScrollPosition& position)
2733 LOG_WITH_STREAM(Scrolling, stream << "FrameView::requestScrollPositionUpdate " << position);
2735 #if ENABLE(ASYNC_SCROLLING)
2736 if (TiledBacking* tiledBacking = this->tiledBacking())
2737 tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size()));
2740 #if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
2741 if (Page* page = frame().page()) {
2742 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2743 return scrollingCoordinator->requestScrollPositionUpdate(*this, position);
2746 UNUSED_PARAM(position);
2752 HostWindow* FrameView::hostWindow() const
2754 auto* page = frame().page();
2757 return &page->chrome();
2760 void FrameView::addTrackedRepaintRect(const FloatRect& r)
2762 if (!m_isTrackingRepaints || r.isEmpty())
2765 FloatRect repaintRect = r;
2766 repaintRect.moveBy(-scrollPosition());
2767 m_trackedRepaintRects.append(repaintRect);
2770 void FrameView::repaintContentRectangle(const IntRect& r)
2772 ASSERT(!frame().ownerElement());
2774 if (!shouldUpdate())
2777 ScrollView::repaintContentRectangle(r);
2780 static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderElement& renderer, unsigned threshold)
2783 for (const RenderObject* descendant = &renderer; descendant; descendant = descendant->nextInPreOrder()) {
2784 if (is<RenderText>(*descendant)) {
2785 count += downcast<RenderText>(*descendant).text()->length();
2786 if (count >= threshold)
2793 bool FrameView::renderedCharactersExceed(unsigned threshold)
2795 if (!frame().contentRenderer())
2797 return countRenderedCharactersInRenderObjectWithThreshold(*frame().contentRenderer(), threshold) >= threshold;
2800 void FrameView::availableContentSizeChanged(AvailableSizeChangeReason reason)
2802 if (Document* document = frame().document()) {
2803 // FIXME: Merge this logic with m_setNeedsLayoutWasDeferred and find a more appropriate
2804 // way of handling potential recursive layouts when the viewport is resized to accomodate
2805 // the content but the content always overflows the viewport. See webkit.org/b/165781.
2806 if (!(layoutPhase() == InViewSizeAdjust && useFixedLayout()))
2807 document->updateViewportUnitsOnResize();
2810 updateLayoutViewport();
2812 ScrollView::availableContentSizeChanged(reason);
2815 bool FrameView::shouldLayoutAfterContentsResized() const
2817 return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2820 void FrameView::updateContentsSize()
2822 // We check to make sure the view is attached to a frame() as this method can
2823 // be triggered before the view is attached by Frame::createView(...) setting
2824 // various values such as setScrollBarModes(...) for example. An ASSERT is
2825 // triggered when a view is layout before being attached to a frame().
2826 if (!frame().view())
2830 if (RenderView* root = m_frame->contentRenderer()) {
2831 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2832 setViewportConstrainedObjectsNeedLayout();
2833 // We must eagerly enter compositing mode because fixed position elements
2834 // will not have been made compositing via a preceding style change before
2835 // m_useCustomFixedPositionLayoutRect was true.
2836 root->compositor().enableCompositingMode();
2841 if (shouldLayoutAfterContentsResized() && needsLayout())
2844 if (RenderView* renderView = this->renderView()) {
2845 if (renderView->usesCompositing())
2846 renderView->compositor().frameViewDidChangeSize();
2850 void FrameView::addedOrRemovedScrollbar()
2852 if (RenderView* renderView = this->renderView()) {
2853 if (renderView->usesCompositing())
2854 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2857 updateTiledBackingAdaptiveSizing();
2860 TiledBacking::Scrollability FrameView::computeScrollability() const
2862 auto* page = frame().page();
2864 // Use smaller square tiles if the Window is not active to facilitate app napping.
2865 if (!page || !page->isWindowActive())
2866 return TiledBacking::HorizontallyScrollable | TiledBacking::VerticallyScrollable;
2868 bool horizontallyScrollable;
2869 bool verticallyScrollable;
2870 bool clippedByAncestorView = static_cast<bool>(m_viewExposedRect);
2874 clippedByAncestorView |= page->enclosedInScrollableAncestorView();
2877 if (delegatesScrolling()) {
2878 IntSize documentSize = contentsSize();
2879 IntSize visibleSize = this->visibleSize();
2881 horizontallyScrollable = clippedByAncestorView || documentSize.width() > visibleSize.width();
2882 verticallyScrollable = clippedByAncestorView || documentSize.height() > visibleSize.height();
2884 horizontallyScrollable = clippedByAncestorView || horizontalScrollbar();
2885 verticallyScrollable = clippedByAncestorView || verticalScrollbar();
2888 TiledBacking::Scrollability scrollability = TiledBacking::NotScrollable;
2889 if (horizontallyScrollable)
2890 scrollability = TiledBacking::HorizontallyScrollable;
2892 if (verticallyScrollable)
2893 scrollability |= TiledBacking::VerticallyScrollable;
2895 return scrollability;
2898 void FrameView::updateTiledBackingAdaptiveSizing()
2900 auto* tiledBacking = this->tiledBacking();
2904 tiledBacking->setScrollability(computeScrollability());
2909 void FrameView::unobscuredContentSizeChanged()
2911 updateTiledBackingAdaptiveSizing();
2916 static LayerFlushThrottleState::Flags determineLayerFlushThrottleState(Page& page)
2918 // We only throttle when constantly receiving new data during the inital page load.
2919 if (!page.progress().isMainLoadProgressing())
2921 // Scrolling during page loading disables throttling.
2922 if (page.mainFrame().view()->wasScrolledByUser())
2924 // Disable for image documents so large GIF animations don't get throttled during loading.
2925 auto* document = page.mainFrame().document();
2926 if (!document || is<ImageDocument>(*document))
2928 return LayerFlushThrottleState::Enabled;
2931 void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2933 if (!frame().page())
2935 auto& page = *frame().page();
2937 LayerFlushThrottleState::Flags flags = LayerFlushThrottleState::UserIsInteracting | determineLayerFlushThrottleState(page);
2938 if (page.chrome().client().adjustLayerFlushThrottling(flags))
2941 if (RenderView* view = renderView())
2942 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2945 void FrameView::loadProgressingStatusChanged()
2947 updateLayerFlushThrottling();
2948 adjustTiledBackingCoverage();
2951 void FrameView::updateLayerFlushThrottling()
2953 Page* page = frame().page();
2957 ASSERT(frame().isMainFrame());
2959 LayerFlushThrottleState::Flags flags = determineLayerFlushThrottleState(*page);
2961 // See if the client is handling throttling.
2962 if (page->chrome().client().adjustLayerFlushThrottling(flags))
2965 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
2966 if (RenderView* renderView = frame->contentRenderer())
2967 renderView->compositor().setLayerFlushThrottlingEnabled(flags & LayerFlushThrottleState::Enabled);
2971 void FrameView::adjustTiledBackingCoverage()
2973 if (!m_speculativeTilingEnabled)
2974 enableSpeculativeTilingIfNeeded();
2976 RenderView* renderView = this->renderView();
2977 if (renderView && renderView->layer() && renderView->layer()->backing())
2978 renderView->layer()->backing()->adjustTiledBackingCoverage();
2980 if (LegacyTileCache* tileCache = legacyTileCache())
2981 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2985 static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2987 Page* page = view.frame().page();
2988 return page && view.isVisuallyNonEmpty() && !page->progress().isMainLoadProgressing();
2991 void FrameView::enableSpeculativeTilingIfNeeded()
2993 ASSERT(!m_speculativeTilingEnabled);
2994 if (m_wasScrolledByUser) {
2995 m_speculativeTilingEnabled = true;
2998 if (!shouldEnableSpeculativeTilingDuringLoading(*this))
3001 if (m_speculativeTilingDelayDisabledForTesting) {
3002 speculativeTilingEnableTimerFired();
3006 if (m_speculativeTilingEnableTimer.isActive())
3008 // Delay enabling a bit as load completion may trigger further loading from scripts.
3009 static const Seconds speculativeTilingEnableDelay { 500_ms };
3010 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
3013 void FrameView::speculativeTilingEnableTimerFired()
3015 if (m_speculativeTilingEnabled)
3017 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
3018 adjustTiledBackingCoverage();
3021 void FrameView::show()
3025 if (frame().isMainFrame()) {
3026 // Turn off speculative tiling for a brief moment after a FrameView appears on screen.
3027 // Note that adjustTiledBackingCoverage() kicks the (500ms) timer to re-enable it.
3028 m_speculativeTilingEnabled = false;
3029 m_wasScrolledByUser = false;
3030 adjustTiledBackingCoverage();
3034 void FrameView::hide()
3037 adjustTiledBackingCoverage();
3040 void FrameView::convertSubtreeLayoutToFullLayout()
3042 ASSERT(m_layoutRoot);
3043 m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No);
3044 m_layoutRoot = nullptr;
3047 void FrameView::layoutTimerFired()
3050 if (!frame().document()->ownerElement())
3051 LOG(Layout, "FrameView %p layout timer fired at %.3fs", this, frame().document()->timeSinceDocumentCreation().value());
3056 void FrameView::scheduleRelayout()
3058 // FIXME: We should assert the page is not in the page cache, but that is causing
3059 // too many false assertions. See <rdar://problem/7218118>.
3060 ASSERT(frame().view() == this);
3063 convertSubtreeLayoutToFullLayout();
3064 if (!m_layoutSchedulingEnabled)
3068 if (!frame().document()->shouldScheduleLayout())
3070 InspectorInstrumentation::didInvalidateLayout(frame());
3071 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
3072 // Also invalidate parent frame starting from the owner element of this frame.
3073 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
3074 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
3076 Seconds delay = frame().document()->minimumLayoutDelay();
3077 if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
3078 unscheduleRelayout();
3080 if (m_layoutTimer.isActive())
3083 m_delayedLayout = delay.value();
3086 if (!frame().document()->ownerElement())
3087 LOG(Layout, "FrameView %p scheduling layout for %.3fs", this, delay.value());
3090 m_layoutTimer.startOneShot(delay);
3093 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
3095 for (RenderObject* r = descendant; r; r = r->container()) {
3102 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
3104 ASSERT(renderView());
3105 const RenderView& renderView = *this->renderView();
3107 // Try to catch unnecessary work during render tree teardown.
3108 ASSERT(!renderView.renderTreeBeingDestroyed());
3109 ASSERT(frame().view() == this);
3111 // When m_layoutRoot is already set, ignore the renderView's needsLayout bit
3112 // since we need to resolve the conflict between the m_layoutRoot and newRelayoutRoot layouts.
3113 if (renderView.needsLayout() && !m_layoutRoot) {
3114 m_layoutRoot = &newRelayoutRoot;
3115 convertSubtreeLayoutToFullLayout();
3119 if (!layoutPending() && m_layoutSchedulingEnabled) {
3120 Seconds delay = renderView.document().minimumLayoutDelay();
3121 ASSERT(!newRelayoutRoot.container() || is<RenderView>(newRelayoutRoot.container()) || !newRelayoutRoot.container()->needsLayout());
3122 m_layoutRoot = &newRelayoutRoot;
3123 InspectorInstrumentation::didInvalidateLayout(frame());
3124 m_delayedLayout = delay.value();
3125 m_layoutTimer.startOneShot(delay);
3129 if (m_layoutRoot == &newRelayoutRoot)
3132 if (!m_layoutRoot) {
3133 // We already have a pending (full) layout. Just mark the subtree for layout.
3134 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
3135 InspectorInstrumentation::didInvalidateLayout(frame());
3139 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
3140 // Keep the current root.
3141 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No, m_layoutRoot);
3142 ASSERT(!m_layoutRoot->container() || is<RenderView>(m_layoutRoot->container()) || !m_layoutRoot->container()->needsLayout());
3146 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
3147 // Re-root at newRelayoutRoot.
3148 m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No, &newRelayoutRoot);
3149 m_layoutRoot = &newRelayoutRoot;
3150 ASSERT(!m_layoutRoot->container() || is<RenderView>(m_layoutRoot->container()) || !m_layoutRoot->container()->needsLayout());
3151 InspectorInstrumentation::didInvalidateLayout(frame());
3154 // Two disjoint subtrees need layout. Mark both of them and issue a full layout instead.
3155 convertSubtreeLayoutToFullLayout();
3156 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
3157 InspectorInstrumentation::didInvalidateLayout(frame());
3160 bool FrameView::layoutPending() const
3162 return m_layoutTimer.isActive();
3165 bool FrameView::needsLayout() const
3167 // This can return true in cases where the document does not have a body yet.
3168 // Document::shouldScheduleLayout takes care of preventing us from scheduling
3169 // layout in that case.
3170 RenderView* renderView = this->renderView();
3171 return layoutPending()
3172 || (renderView && renderView->needsLayout())
3174 || (m_deferSetNeedsLayoutCount && m_setNeedsLayoutWasDeferred);
3177 void FrameView::setNeedsLayout()
3179 if (m_deferSetNeedsLayoutCount) {
3180 m_setNeedsLayoutWasDeferred = true;
3184 if (auto* renderView = this->renderView()) {
3185 ASSERT(!renderView->inHitTesting());
3186 renderView->setNeedsLayout();
3190 void FrameView::unscheduleRelayout()
3192 if (m_postLayoutTasksTimer.isActive())
3193 m_postLayoutTasksTimer.stop();
3195 if (!m_layoutTimer.isActive())
3199 if (!frame().document()->ownerElement())
3200 LOG(Layout, "FrameView %p layout timer unscheduled at %.3fs", this, frame().document()->timeSinceDocumentCreation().value());
3203 m_layoutTimer.stop();
3204 m_delayedLayout = false;
3207 void FrameView::serviceScriptedAnimations()
3209 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext()) {
3210 frame->view()->serviceScrollAnimations();
3211 frame->animation().serviceAnimations();
3214 if (!frame().document() || !frame().document()->domWindow())
3217 Vector<RefPtr<Document>> documents;
3218 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext())
3219 documents.append(frame->document());
3221 double timestamp = frame().document()->domWindow()->nowTimestamp();
3222 for (auto& document : documents)
3223 document->serviceScriptedAnimations(timestamp);
3226 bool FrameView::isTransparent() const
3228 return m_isTransparent;
3231 void FrameView::setTransparent(bool isTransparent)
3233 if (m_isTransparent == isTransparent)
3236 m_isTransparent = isTransparent;
3238 // setTransparent can be called in the window between FrameView initialization
3239 // and switching in the new Document; this means that the RenderView that we
3240 // retrieve is actually attached to the previous Document, which is going away,
3241 // and must not update compositing layers.
3242 if (!isViewForDocumentInFrame())
3245 renderView()->compositor().rootBackgroundTransparencyChanged();
3248 bool FrameView::hasOpaqueBackground() const
3250 return !m_isTransparent && m_baseBackgroundColor.isOpaque();
3253 Color FrameView::baseBackgroundColor() const
3255 return m_baseBackgroundColor;
3258 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
3260 bool wasOpaque = m_baseBackgroundColor.isOpaque();
3262 if (!backgroundColor.isValid())
3263 m_baseBackgroundColor = Color::white;
3265 m_baseBackgroundColor = backgroundColor;
3267 if (!isViewForDocumentInFrame())
3270 recalculateScrollbarOverlayStyle();
3272 if (m_baseBackgroundColor.isOpaque() != wasOpaque)
3273 renderView()->compositor().rootBackgroundTransparencyChanged();
3276 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
3278 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
3279 if (FrameView* view = frame->view()) {
3280 view->setTransparent(transparent);
3281 view->setBaseBackgroundColor(backgroundColor);
3286 bool FrameView::hasExtendedBackgroundRectForPainting() const
3288 TiledBacking* tiledBacking = this->tiledBacking();
3292 return tiledBacking->hasMargins();
3295 void FrameView::updateExtendBackgroundIfNecessary()
3297 ExtendedBackgroundMode mode = calculateExtendedBackgroundMode();
3298 if (mode == ExtendedBackgroundModeNone)
3301 updateTilesForExtendedBackgroundMode(mode);
3304 FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
3307 // <rdar://problem/16201373>
3308 return ExtendedBackgroundModeNone;
3310 if (!frame().settings().backgroundShouldExtendBeyondPage())
3311 return ExtendedBackgroundModeNone;
3313 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
3314 // that the background rect needs to be extended for painting. Simple backgrounds can be extended
3315 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
3316 // such as images, require extending the background rect to continue painting into the extended
3317 // region. This function finds out if it is necessary to extend the background rect for painting.
3319 if (!frame().isMainFrame())
3320 return ExtendedBackgroundModeNone;
3322 Document* document = frame().document();
3324 return ExtendedBackgroundModeNone;
3327 return ExtendedBackgroundModeNone;
3329 auto* rootBackgroundRenderer = renderView()->rendererForRootBackground();
3330 if (!rootBackgroundRenderer)
3331 return ExtendedBackgroundModeNone;
3333 if (!rootBackgroundRenderer->style().hasBackgroundImage())
3334 return ExtendedBackgroundModeNone;
3336 ExtendedBackgroundMode mode = ExtendedBackgroundModeNone;
3337 if (rootBackgroundRenderer->style().backgroundRepeatX() == RepeatFill)
3338 mode |= ExtendedBackgroundModeHorizontal;
3339 if (rootBackgroundRenderer->style().backgroundRepeatY() == RepeatFill)
3340 mode |= ExtendedBackgroundModeVertical;
3346 void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
3348 RenderView* renderView = this->renderView();
3352 RenderLayerBacking* backing = renderView->layer()->backing();
3356 TiledBacking* tiledBacking = backing->tiledBacking();
3360 ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone;
3361 if (tiledBacking->hasVerticalMargins())
3362 existingMode |= ExtendedBackgroundModeVertical;
3363 if (tiledBacking->hasHorizontalMargins())
3364 existingMode |= ExtendedBackgroundModeHorizontal;
3366 if (existingMode == mode)
3369 renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor());
3370 backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical);
3373 IntRect FrameView::extendedBackgroundRectForPainting() const
3375 TiledBacking* tiledBacking = this->tiledBacking();
3379 RenderView* renderView = this->renderView();
3383 LayoutRect extendedRect = renderView->unextendedBackgroundRect();
3384 if (!tiledBacking->hasMargins())
3385 return snappedIntRect(extendedRect);
3387 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
3388 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
3389 return snappedIntRect(extendedRect);
3392 bool FrameView::shouldUpdateWhileOffscreen() const
3394 return m_shouldUpdateWhileOffscreen;
3397 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
3399 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
3402 bool FrameView::shouldUpdate() const
3404 if (isOffscreen() && !shouldUpdateWhileOffscreen())
3409 void FrameView::scrollToAnchor()
3411 RefPtr<ContainerNode> anchorNode = m_maintainScrollPositionAnchor;
3415 if (!anchorNode->renderer())
3419 bool insideFixed = false;
3420 if (anchorNode != frame().document() && anchorNode->renderer())
3421 rect = anchorNode->renderer()->absoluteAnchorRect(&insideFixed);
3423 // Scroll nested layers and frames to reveal the anchor.
3424 // Align to the top and to the closest side (this matches other browsers).
3425 if (anchorNode->renderer()->style().isHorizontalWritingMode())
3426 anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
3427 else if (anchorNode->renderer()->style().isFlippedBlocksWritingMode())
3428 anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
3430 anchorNode->renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, rect, insideFixed, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
3432 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
3433 cache->handleScrolledToAnchor(anchorNode.get());
3435 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
3436 m_maintainScrollPositionAnchor = anchorNode;
3439 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
3441 // No need to update if it's already crashed or known to be missing.
3442 if (embeddedObject.isPluginUnavailable())
3445 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
3447 if (embeddedObject.isSnapshottedPlugIn()) {
3448 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
3449 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
3450 pluginElement.checkSnapshotStatus();
3455 auto weakRenderer = makeWeakPtr(embeddedObject);
3457 // FIXME: This could turn into a real virtual dispatch if we defined
3458 // updateWidget(PluginCreationOption) on HTMLElement.
3459 if (is<HTMLPlugInImageElement>(element)) {
3460 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
3461 if (pluginElement.needsCheckForSizeChange()) {
3462 pluginElement.checkSnapshotStatus();
3465 if (pluginElement.needsWidgetUpdate())
3466 pluginElement.updateWidget(CreatePlugins::Yes);
3468 ASSERT_NOT_REACHED();
3470 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
3474 auto ignoreWidgetState = embeddedObject.updateWidgetPosition();
3475 UNUSED_PARAM(ignoreWidgetState);
3478 bool FrameView::updateEmbeddedObjects()
3480 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
3483 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
3485 // Insert a marker for where we should stop.
3486 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
3487 m_embeddedObjectsToUpdate->add(nullptr);
3489 while (!m_embeddedObjectsToUpdate->isEmpty()) {
3490 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
3491 if (!embeddedObject)
3493 updateEmbeddedObject(*embeddedObject);
3496 return m_embeddedObjectsToUpdate->isEmpty();
3499 void FrameView::updateEmbeddedObjectsTimerFired()
3501 RefPtr<FrameView> protectedThis(this);
3502 m_updateEmbeddedObjectsTimer.stop();
3503 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
3504 if (updateEmbeddedObjects())
3509 void FrameView::flushAnyPendingPostLayoutTasks()
3511 if (m_postLayoutTasksTimer.isActive())
3512 performPostLayoutTasks();
3513 if (m_updateEmbeddedObjectsTimer.isActive())
3514 updateEmbeddedObjectsTimerFired();
3517 void FrameView::queuePostLayoutCallback(Function<void()>&& callback)
3519 m_postLayoutCallbackQueue.append(WTFMove(callback));
3522 void FrameView::flushPostLayoutTasksQueue()
3524 if (m_nestedLayoutCount > 1)
3527 if (!m_postLayoutCallbackQueue.size())
3530 Vector<Function<void()>> queue = WTFMove(m_postLayoutCallbackQueue);
3531 for (auto& task : queue)
3535 void FrameView::performPostLayoutTasks()
3537 // FIXME: We should not run any JavaScript code in this function.
3538 LOG(Layout, "FrameView %p performPostLayoutTasks", this);
3540 m_postLayoutTasksTimer.stop();
3542 frame().selection().updateAppearanceAfterLayout();
3544 flushPostLayoutTasksQueue();
3546 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
3547 fireLayoutRelatedMilestonesIfNeeded();
3550 // Only send layout-related delegate callbacks synchronously for the main frame to
3551 // avoid re-entering layout for the main frame while delivering a layout-related delegate
3552 // callback for a subframe.
3553 if (frame().isMainFrame()) {
3554 if (Page* page = frame().page())
3555 page->chrome().client().didLayout();
3559 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
3560 // with didLayout(LayoutMilestones).
3561 frame().loader().client().dispatchDidLayout();
3563 updateWidgetPositions();
3565 #if ENABLE(CSS_SCROLL_SNAP)
3566 updateSnapOffsets();
3568 m_updateEmbeddedObjectsTimer.startOneShot(0_s);
3570 if (auto* page = frame().page()) {
3571 if (auto* scrollingCoordinator = page->scrollingCoordinator())
3572 scrollingCoordinator->frameViewLayoutUpdated(*this);
3575 if (RenderView* renderView = this->renderView()) {
3576 if (renderView->usesCompositing())
3577 renderView->compositor().frameViewDidLayout();
3582 sendResizeEventIfNeeded();
3584 updateLayoutViewport();
3585 viewportContentsChanged();
3587 updateScrollSnapState();
3589 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
3590 cache->performDeferredCacheUpdate();
3593 IntSize FrameView::sizeForResizeEvent() const
3596 if (m_useCustomSizeForResizeEvent)
3597 return m_customSizeForResizeEvent;
3599 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
3600 return fixedLayoutSize();
3601 return visibleContentRectIncludingScrollbars().size();
3604 void FrameView::sendResizeEventIfNeeded()
3606 if (isInRenderTreeLayout() || needsLayout())
3609 RenderView* renderView = this->renderView();
3610 if (!renderView || renderView->printing())
3613 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
3616 IntSize currentSize = sizeForResizeEvent();
3617 float currentZoomFactor = renderView->style().zoom();
3619 if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor)
3622 m_lastViewportSize = currentSize;
3623 m_lastZoomFactor = currentZoomFactor;
3629 // Don't send the resize event if the document is loading. Some pages automatically reload
3630 // when the window is resized; Safari on iOS often resizes the window while setting up its
3631 // viewport. This obviously can cause problems.
3632 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
3633 if (documentLoader->isLoadingInAPISense())
3638 bool isMainFrame = frame().isMainFrame();
3639 bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize;
3641 LOG(Events, "FrameView %p sendResizeEventIfNeeded sending resize event, size %dx%d (canSendResizeEventSynchronously %d)", this, currentSize.width(), currentSize.height(), canSendResizeEventSynchronously);
3643 Ref<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
3644 if (canSendResizeEventSynchronously)
3645 frame().document()->dispatchWindowEvent(resizeEvent);
3647 // FIXME: Queueing this event for an unpredictable time in the future seems
3648 // intrinsically racy. By the time this resize event fires, the frame might
3649 // be resized again, so we could end up with two resize events for the same size.
3650 frame().document()->enqueueWindowEvent(WTFMove(resizeEvent));
3653 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
3654 if (Page* page = frame().page()) {
3655 if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient())
3656 inspectorClient->didResizeMainFrame(&frame());
3661 void FrameView::willStartLiveResize()
3663 ScrollView::willStartLiveResize();
3664 adjustTiledBackingCoverage();
3667 void FrameView::willEndLiveResize()
3669 ScrollView::willEndLiveResize();
3670 adjustTiledBackingCoverage();