2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Dirk Mueller <mueller@kde.org>
6 * Copyright (C) 2004-2008, 2013-2015 Apple Inc. All rights reserved.
7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9 * Copyright (C) 2009 Google Inc. All rights reserved.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
28 #include "FrameView.h"
30 #include "AXObjectCache.h"
31 #include "AnimationController.h"
32 #include "BackForwardController.h"
33 #include "CachedImage.h"
34 #include "CachedResourceLoader.h"
36 #include "ChromeClient.h"
37 #include "DOMWindow.h"
38 #include "DebugPageOverlays.h"
39 #include "DocumentMarkerController.h"
40 #include "EventHandler.h"
41 #include "FloatRect.h"
42 #include "FocusController.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameSelection.h"
46 #include "FrameTree.h"
47 #include "GraphicsContext.h"
48 #include "HTMLBodyElement.h"
49 #include "HTMLDocument.h"
50 #include "HTMLFrameElement.h"
51 #include "HTMLFrameSetElement.h"
52 #include "HTMLNames.h"
53 #include "HTMLPlugInImageElement.h"
54 #include "ImageDocument.h"
55 #include "InspectorClient.h"
56 #include "InspectorController.h"
57 #include "InspectorInstrumentation.h"
59 #include "MainFrame.h"
60 #include "MemoryCache.h"
61 #include "MemoryPressureHandler.h"
62 #include "OverflowEvent.h"
63 #include "PageCache.h"
64 #include "PageOverlayController.h"
65 #include "ProgressTracker.h"
66 #include "RenderEmbeddedObject.h"
67 #include "RenderFullScreen.h"
68 #include "RenderIFrame.h"
69 #include "RenderInline.h"
70 #include "RenderLayer.h"
71 #include "RenderLayerBacking.h"
72 #include "RenderLayerCompositor.h"
73 #include "RenderSVGRoot.h"
74 #include "RenderScrollbar.h"
75 #include "RenderScrollbarPart.h"
76 #include "RenderStyle.h"
77 #include "RenderText.h"
78 #include "RenderTheme.h"
79 #include "RenderView.h"
80 #include "RenderWidget.h"
81 #include "SVGDocument.h"
82 #include "SVGSVGElement.h"
83 #include "ScriptedAnimationController.h"
84 #include "ScrollAnimator.h"
85 #include "ScrollingCoordinator.h"
87 #include "StyleResolver.h"
88 #include "TextResourceDecoder.h"
89 #include "TextStream.h"
90 #include "TiledBacking.h"
91 #include "WheelEventTestTrigger.h"
93 #include <wtf/CurrentTime.h>
95 #include <wtf/SystemTracing.h>
96 #include <wtf/TemporaryChange.h>
98 #if USE(COORDINATED_GRAPHICS)
99 #include "TiledBackingStore.h"
102 #if ENABLE(TEXT_AUTOSIZING)
103 #include "TextAutosizer.h"
106 #if ENABLE(CSS_SCROLL_SNAP)
107 #include "AxisScrollSnapOffsets.h"
111 #include "DocumentLoader.h"
112 #include "LegacyTileCache.h"
117 using namespace HTMLNames;
119 double FrameView::sCurrentPaintTimeStamp = 0.0;
121 // The maximum number of updateEmbeddedObjects iterations that should be done before returning.
122 static const unsigned maxUpdateEmbeddedObjectsIterations = 2;
124 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
126 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
127 if (didFullRepaint) {
128 flags &= ~RenderLayer::CheckForRepaint;
129 flags |= RenderLayer::NeedsFullRepaintInBacking;
131 if (isRelayoutingSubtree && layer->enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers))
132 flags |= RenderLayer::UpdatePagination;
136 Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style)
138 EOverflow overflow = style.overflowY();
139 if (overflow != OPAGEDX && overflow != OPAGEDY)
140 return Pagination::Unpaginated;
142 bool isHorizontalWritingMode = style.isHorizontalWritingMode();
143 TextDirection textDirection = style.direction();
144 WritingMode writingMode = style.writingMode();
146 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode
147 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode
148 // is vertical, then the direction of the verticality dictates the choice.
149 if (overflow == OPAGEDX) {
150 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode)
151 return Pagination::LeftToRightPaginated;
152 return Pagination::RightToLeftPaginated;
155 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode
156 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode
157 // is vertical, then we use TextDirection to choose between those options.
158 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL))
159 return Pagination::TopToBottomPaginated;
160 return Pagination::BottomToTopPaginated;
163 class SubtreeLayoutStateMaintainer {
165 SubtreeLayoutStateMaintainer(RenderElement* subtreeLayoutRoot)
166 : m_layoutRoot(subtreeLayoutRoot)
169 RenderView& view = m_layoutRoot->view();
170 view.pushLayoutState(*m_layoutRoot);
171 m_disableLayoutState = view.shouldDisableLayoutStateForSubtree(m_layoutRoot);
172 if (m_disableLayoutState)
173 view.disableLayoutState();
177 ~SubtreeLayoutStateMaintainer()
180 RenderView& view = m_layoutRoot->view();
181 view.popLayoutState(*m_layoutRoot);
182 if (m_disableLayoutState)
183 view.enableLayoutState();
188 RenderElement* m_layoutRoot { nullptr };
189 bool m_disableLayoutState { false };
192 FrameView::FrameView(Frame& frame)
194 , m_canHaveScrollbars(true)
195 , m_layoutTimer(*this, &FrameView::layoutTimerFired)
196 , m_layoutPhase(OutsideLayout)
197 , m_inSynchronousPostLayout(false)
198 , m_postLayoutTasksTimer(*this, &FrameView::performPostLayoutTasks)
199 , m_updateEmbeddedObjectsTimer(*this, &FrameView::updateEmbeddedObjectsTimerFired)
200 , m_isTransparent(false)
201 , m_baseBackgroundColor(Color::white)
202 , m_mediaType("screen")
203 , m_overflowStatusDirty(true)
204 , m_wasScrolledByUser(false)
205 , m_inProgrammaticScroll(false)
206 , m_safeToPropagateScrollToParent(true)
207 , m_delayedScrollEventTimer(*this, &FrameView::sendScrollEvent)
208 , m_isTrackingRepaints(false)
209 , m_shouldUpdateWhileOffscreen(true)
210 , m_exposedRect(FloatRect::infiniteRect())
211 , m_deferSetNeedsLayoutCount(0)
212 , m_setNeedsLayoutWasDeferred(false)
213 , m_speculativeTilingEnabled(false)
214 , m_speculativeTilingEnableTimer(*this, &FrameView::speculativeTilingEnableTimerFired)
216 , m_useCustomFixedPositionLayoutRect(false)
217 , m_useCustomSizeForResizeEvent(false)
219 , m_hasOverrideViewportSize(false)
220 , m_shouldAutoSize(false)
221 , m_inAutoSize(false)
222 , m_didRunAutosize(false)
223 , m_autoSizeFixedMinimumHeight(0)
226 , m_milestonesPendingPaint(0)
227 , m_visualUpdatesAllowedByClient(true)
228 , m_hasFlippedBlockRenderers(false)
229 , m_scrollPinningBehavior(DoNotPin)
233 #if ENABLE(RUBBER_BANDING)
234 ScrollElasticity verticalElasticity = ScrollElasticityNone;
235 ScrollElasticity horizontalElasticity = ScrollElasticityNone;
236 if (m_frame->isMainFrame()) {
237 verticalElasticity = m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed;
238 horizontalElasticity = m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed;
239 } else if (m_frame->settings().rubberBandingForSubScrollableRegionsEnabled()) {
240 verticalElasticity = ScrollElasticityAutomatic;
241 horizontalElasticity = ScrollElasticityAutomatic;
244 ScrollableArea::setVerticalScrollElasticity(verticalElasticity);
245 ScrollableArea::setHorizontalScrollElasticity(horizontalElasticity);
249 Ref<FrameView> FrameView::create(Frame& frame)
251 Ref<FrameView> view = adoptRef(*new FrameView(frame));
256 Ref<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
258 Ref<FrameView> view = adoptRef(*new FrameView(frame));
259 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
264 FrameView::~FrameView()
266 if (m_postLayoutTasksTimer.isActive())
267 m_postLayoutTasksTimer.stop();
269 removeFromAXObjectCache();
272 // Custom scrollbars should already be destroyed at this point
273 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
274 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
276 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
277 setHasVerticalScrollbar(false);
279 ASSERT(!m_scrollCorner);
281 ASSERT(frame().view() != this || !frame().contentRenderer());
284 void FrameView::reset()
286 m_cannotBlitToWindow = false;
287 m_isOverlapped = false;
288 m_contentIsOpaque = false;
289 m_layoutTimer.stop();
290 m_layoutRoot = nullptr;
291 m_delayedLayout = false;
292 m_needsFullRepaint = true;
293 m_layoutSchedulingEnabled = true;
294 m_layoutPhase = OutsideLayout;
295 m_inSynchronousPostLayout = false;
297 m_nestedLayoutCount = 0;
298 m_postLayoutTasksTimer.stop();
299 m_updateEmbeddedObjectsTimer.stop();
300 m_firstLayout = true;
301 m_firstLayoutCallbackPending = false;
302 m_wasScrolledByUser = false;
303 m_safeToPropagateScrollToParent = true;
304 m_delayedScrollEventTimer.stop();
305 m_lastViewportSize = IntSize();
306 m_lastZoomFactor = 1.0f;
307 m_isTrackingRepaints = false;
308 m_trackedRepaintRects.clear();
310 m_paintBehavior = PaintBehaviorNormal;
311 m_isPainting = false;
312 m_visuallyNonEmptyCharacterCount = 0;
313 m_visuallyNonEmptyPixelCount = 0;
314 m_isVisuallyNonEmpty = false;
315 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
316 m_viewportIsStable = true;
317 m_maintainScrollPositionAnchor = nullptr;
320 void FrameView::removeFromAXObjectCache()
322 if (AXObjectCache* cache = axObjectCache()) {
323 if (HTMLFrameOwnerElement* owner = frame().ownerElement())
324 cache->childrenChanged(owner->renderer());
329 void FrameView::resetScrollbars()
331 // Reset the document's scrollbars back to our defaults before we yield the floor.
332 m_firstLayout = true;
333 setScrollbarsSuppressed(true);
334 if (m_canHaveScrollbars)
335 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
337 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
338 setScrollbarsSuppressed(false);
341 void FrameView::resetScrollbarsAndClearContentsSize()
345 setScrollbarsSuppressed(true);
346 setContentsSize(IntSize());
347 setScrollbarsSuppressed(false);
350 void FrameView::init()
354 m_margins = LayoutSize(-1, -1); // undefined
355 m_size = LayoutSize();
357 // Propagate the marginwidth/height and scrolling modes to the view.
358 Element* ownerElement = frame().ownerElement();
359 if (is<HTMLFrameElementBase>(ownerElement)) {
360 HTMLFrameElementBase& frameElement = downcast<HTMLFrameElementBase>(*ownerElement);
361 if (frameElement.scrollingMode() == ScrollbarAlwaysOff)
362 setCanHaveScrollbars(false);
363 LayoutUnit marginWidth = frameElement.marginWidth();
364 LayoutUnit marginHeight = frameElement.marginHeight();
365 if (marginWidth != -1)
366 setMarginWidth(marginWidth);
367 if (marginHeight != -1)
368 setMarginHeight(marginHeight);
371 Page* page = frame().page();
372 if (page && page->chrome().client().shouldPaintEntireContents())
373 setPaintsEntireContents(true);
376 void FrameView::prepareForDetach()
378 detachCustomScrollbars();
379 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
380 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
381 removeFromAXObjectCache();
383 if (frame().page()) {
384 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
385 scrollingCoordinator->willDestroyScrollableArea(*this);
389 void FrameView::detachCustomScrollbars()
391 Scrollbar* horizontalBar = horizontalScrollbar();
392 if (horizontalBar && horizontalBar->isCustomScrollbar())
393 setHasHorizontalScrollbar(false);
395 Scrollbar* verticalBar = verticalScrollbar();
396 if (verticalBar && verticalBar->isCustomScrollbar())
397 setHasVerticalScrollbar(false);
399 m_scrollCorner = nullptr;
402 void FrameView::recalculateScrollbarOverlayStyle()
404 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
405 WTF::Optional<ScrollbarOverlayStyle> clientOverlayStyle = frame().page() ? frame().page()->chrome().client().preferredScrollbarOverlayStyle() : ScrollbarOverlayStyleDefault;
406 if (clientOverlayStyle) {
407 if (clientOverlayStyle.value() != oldOverlayStyle)
408 setScrollbarOverlayStyle(clientOverlayStyle.value());
412 ScrollbarOverlayStyle computedOverlayStyle = ScrollbarOverlayStyleDefault;
414 Color backgroundColor = documentBackgroundColor();
415 if (backgroundColor.isValid()) {
416 // Reduce the background color from RGB to a lightness value
417 // and determine which scrollbar style to use based on a lightness
419 double hue, saturation, lightness;
420 backgroundColor.getHSL(hue, saturation, lightness);
421 if (lightness <= .5 && backgroundColor.alpha() > 0)
422 computedOverlayStyle = ScrollbarOverlayStyleLight;
425 if (oldOverlayStyle != computedOverlayStyle)
426 setScrollbarOverlayStyle(computedOverlayStyle);
429 void FrameView::clear()
431 setCanBlitOnScroll(true);
435 setScrollbarsSuppressed(true);
438 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
439 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
440 if (LegacyTileCache* tileCache = legacyTileCache())
441 tileCache->setTilingMode(LegacyTileCache::Disabled);
446 void FrameView::didReplaceMultipartContent()
448 // Re-enable tile updates that were disabled in clear().
449 if (LegacyTileCache* tileCache = legacyTileCache())
450 tileCache->setTilingMode(LegacyTileCache::Normal);
454 bool FrameView::didFirstLayout() const
456 return !m_firstLayout;
459 void FrameView::invalidateRect(const IntRect& rect)
462 if (HostWindow* window = hostWindow())
463 window->invalidateContentsAndRootView(rect);
467 RenderWidget* renderer = frame().ownerRenderer();
471 IntRect repaintRect = rect;
472 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
473 renderer->borderTop() + renderer->paddingTop());
474 renderer->repaintRectangle(repaintRect);
477 void FrameView::setFrameRect(const IntRect& newRect)
479 Ref<FrameView> protect(*this);
480 IntRect oldRect = frameRect();
481 if (newRect == oldRect)
484 #if ENABLE(TEXT_AUTOSIZING)
485 // Autosized font sizes depend on the width of the viewing area.
486 if (newRect.width() != oldRect.width()) {
487 if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) {
488 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
489 frame().document()->textAutosizer()->recalculateMultipliers();
494 ScrollView::setFrameRect(newRect);
496 updateScrollableAreaSet();
498 if (RenderView* renderView = this->renderView()) {
499 if (renderView->usesCompositing())
500 renderView->compositor().frameViewDidChangeSize();
503 if (frame().isMainFrame())
504 frame().mainFrame().pageOverlayController().didChangeViewSize();
506 viewportContentsChanged();
509 #if ENABLE(REQUEST_ANIMATION_FRAME)
510 bool FrameView::scheduleAnimation()
512 if (HostWindow* window = hostWindow()) {
513 window->scheduleAnimation();
520 void FrameView::setMarginWidth(LayoutUnit w)
522 // make it update the rendering area when set
523 m_margins.setWidth(w);
526 void FrameView::setMarginHeight(LayoutUnit h)
528 // make it update the rendering area when set
529 m_margins.setHeight(h);
532 bool FrameView::frameFlatteningEnabled() const
534 return frame().settings().frameFlatteningEnabled();
537 bool FrameView::isFrameFlatteningValidForThisFrame() const
539 if (!frameFlatteningEnabled())
542 HTMLFrameOwnerElement* owner = frame().ownerElement();
546 // Frame flattening is valid only for <frame> and <iframe>.
547 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
550 bool FrameView::avoidScrollbarCreation() const
552 // with frame flattening no subframe can have scrollbars
553 // but we also cannot turn scrollbars off as we determine
554 // our flattening policy using that.
555 return isFrameFlatteningValidForThisFrame();
558 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
560 m_canHaveScrollbars = canHaveScrollbars;
561 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
564 void FrameView::updateCanHaveScrollbars()
568 scrollbarModes(hMode, vMode);
569 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
570 setCanHaveScrollbars(false);
572 setCanHaveScrollbars(true);
575 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
577 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
578 return ScrollView::createScrollbar(orientation);
580 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
581 Document* doc = frame().document();
583 // Try the <body> element first as a scrollbar source.
584 HTMLElement* body = doc ? doc->bodyOrFrameset() : nullptr;
585 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
586 return RenderScrollbar::createCustomScrollbar(*this, orientation, body);
588 // If the <body> didn't have a custom style, then the root element might.
589 Element* docElement = doc ? doc->documentElement() : nullptr;
590 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
591 return RenderScrollbar::createCustomScrollbar(*this, orientation, docElement);
593 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
594 RenderWidget* frameRenderer = frame().ownerRenderer();
595 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
596 return RenderScrollbar::createCustomScrollbar(*this, orientation, nullptr, &frame());
598 // Nobody set a custom style, so we just use a native scrollbar.
599 return ScrollView::createScrollbar(orientation);
602 void FrameView::setContentsSize(const IntSize& size)
604 if (size == contentsSize())
607 m_deferSetNeedsLayoutCount++;
609 ScrollView::setContentsSize(size);
612 Page* page = frame().page();
616 updateScrollableAreaSet();
618 page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
620 if (frame().isMainFrame()) {
621 frame().mainFrame().pageOverlayController().didChangeDocumentSize();
622 PageCache::singleton().markPagesForContentsSizeChanged(*page);
625 ASSERT(m_deferSetNeedsLayoutCount);
626 m_deferSetNeedsLayoutCount--;
628 if (!m_deferSetNeedsLayoutCount)
629 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
632 void FrameView::adjustViewSize()
634 RenderView* renderView = this->renderView();
638 ASSERT(frame().view() == this);
640 const IntRect rect = renderView->documentRect();
641 const IntSize& size = rect.size();
642 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
644 LOG_WITH_STREAM(Layout, stream << "FrameView " << this << " adjustViewSize: unscaled document rect changed to " << renderView->unscaledDocumentRect() << " (scaled to " << size << ")");
646 setContentsSize(size);
649 void FrameView::applyOverflowToViewport(const RenderElement& renderer, ScrollbarMode& hMode, ScrollbarMode& vMode)
651 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
652 // overflow:hidden and overflow:scroll on <body> as applying to the document's
653 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
654 // use the root element.
656 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
657 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
660 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
662 EOverflow overflowX = renderer.style().overflowX();
663 EOverflow overflowY = renderer.style().overflowY();
665 if (is<RenderSVGRoot>(renderer)) {
666 // FIXME: evaluate if we can allow overflow for these cases too.
667 // Overflow is always hidden when stand-alone SVG documents are embedded.
668 if (downcast<RenderSVGRoot>(renderer).isEmbeddedThroughFrameContainingSVGDocument()) {
677 hMode = ScrollbarAuto;
679 hMode = ScrollbarAlwaysOff;
682 hMode = ScrollbarAlwaysOn;
685 hMode = ScrollbarAuto;
688 // Don't set it at all.
695 vMode = ScrollbarAuto;
697 vMode = ScrollbarAlwaysOff;
700 vMode = ScrollbarAlwaysOn;
703 vMode = ScrollbarAuto;
706 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
711 void FrameView::applyPaginationToViewport()
713 Document* document = frame().document();
714 auto* documentElement = document->documentElement();
715 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
716 RenderElement* documentOrBodyRenderer = documentRenderer;
717 auto* body = document->body();
718 if (body && body->renderer())
719 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(*documentElement) ? body->renderer() : documentRenderer;
721 Pagination pagination;
723 if (!documentOrBodyRenderer) {
724 setPagination(pagination);
728 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
729 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
730 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
731 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
734 setPagination(pagination);
737 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
739 m_viewportRendererType = ViewportRendererType::None;
741 const HTMLFrameOwnerElement* owner = frame().ownerElement();
742 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
743 hMode = ScrollbarAlwaysOff;
744 vMode = ScrollbarAlwaysOff;
748 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
749 hMode = ScrollbarAuto;
750 vMode = ScrollbarAuto;
752 hMode = ScrollbarAlwaysOff;
753 vMode = ScrollbarAlwaysOff;
759 auto* document = frame().document();
763 auto* documentElement = document->documentElement();
764 if (!documentElement)
767 auto* bodyOrFrameset = document->bodyOrFrameset();
768 auto* rootRenderer = documentElement->renderer();
769 if (!bodyOrFrameset || !bodyOrFrameset->renderer()) {
771 applyOverflowToViewport(*rootRenderer, hMode, vMode);
772 m_viewportRendererType = ViewportRendererType::Document;
777 if (is<HTMLFrameSetElement>(*bodyOrFrameset) && !frameFlatteningEnabled()) {
778 vMode = ScrollbarAlwaysOff;
779 hMode = ScrollbarAlwaysOff;
783 if (is<HTMLBodyElement>(*bodyOrFrameset) && rootRenderer) {
784 // It's sufficient to just check the X overflow,
785 // since it's illegal to have visible in only one direction.
786 if (rootRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(documentElement)) {
787 auto* bodyRenderer = bodyOrFrameset->renderer();
789 applyOverflowToViewport(*bodyRenderer, hMode, vMode);
790 m_viewportRendererType = ViewportRendererType::Body;
793 applyOverflowToViewport(*rootRenderer, hMode, vMode);
794 m_viewportRendererType = ViewportRendererType::Document;
799 void FrameView::willRecalcStyle()
801 RenderView* renderView = this->renderView();
805 renderView->compositor().willRecalcStyle();
808 bool FrameView::updateCompositingLayersAfterStyleChange()
810 RenderView* renderView = this->renderView();
814 // If we expect to update compositing after an incipient layout, don't do so here.
815 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
818 return renderView->compositor().didRecalcStyleWithNoPendingLayout();
821 void FrameView::updateCompositingLayersAfterLayout()
823 RenderView* renderView = this->renderView();
827 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
828 renderView->compositor().cacheAcceleratedCompositingFlags();
829 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
832 void FrameView::clearBackingStores()
834 RenderView* renderView = this->renderView();
838 RenderLayerCompositor& compositor = renderView->compositor();
839 ASSERT(compositor.inCompositingMode());
840 compositor.enableCompositingMode(false);
841 compositor.clearBackingForAllLayers();
844 void FrameView::restoreBackingStores()
846 RenderView* renderView = this->renderView();
850 RenderLayerCompositor& compositor = renderView->compositor();
851 compositor.enableCompositingMode(true);
852 compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
855 GraphicsLayer* FrameView::layerForScrolling() const
857 RenderView* renderView = this->renderView();
860 return renderView->compositor().scrollLayer();
863 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
865 RenderView* renderView = this->renderView();
868 return renderView->compositor().layerForHorizontalScrollbar();
871 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
873 RenderView* renderView = this->renderView();
876 return renderView->compositor().layerForVerticalScrollbar();
879 GraphicsLayer* FrameView::layerForScrollCorner() const
881 RenderView* renderView = this->renderView();
884 return renderView->compositor().layerForScrollCorner();
887 TiledBacking* FrameView::tiledBacking() const
889 RenderView* renderView = this->renderView();
893 RenderLayerBacking* backing = renderView->layer()->backing();
897 return backing->graphicsLayer()->tiledBacking();
900 uint64_t FrameView::scrollLayerID() const
902 RenderView* renderView = this->renderView();
906 RenderLayerBacking* backing = renderView->layer()->backing();
910 return backing->scrollingNodeIDForRole(Scrolling);
913 ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
915 RenderView* renderView = this->renderView();
919 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
922 #if ENABLE(RUBBER_BANDING)
923 GraphicsLayer* FrameView::layerForOverhangAreas() const
925 RenderView* renderView = this->renderView();
928 return renderView->compositor().layerForOverhangAreas();
931 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
933 RenderView* renderView = this->renderView();
937 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
940 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
942 RenderView* renderView = this->renderView();
946 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
949 #endif // ENABLE(RUBBER_BANDING)
951 #if ENABLE(CSS_SCROLL_SNAP)
952 void FrameView::updateSnapOffsets()
954 if (!frame().document())
957 // FIXME: Should we allow specifying snap points through <html> tags too?
958 HTMLElement* body = frame().document()->bodyOrFrameset();
959 if (!renderView() || !body || !body->renderer())
962 updateSnapOffsetsForScrollableArea(*this, *body, *renderView(), body->renderer()->style());
965 bool FrameView::isScrollSnapInProgress() const
967 if (scrollbarsSuppressed())
970 // If the scrolling thread updates the scroll position for this FrameView, then we should return
971 // ScrollingCoordinator::isScrollSnapInProgress().
972 if (Page* page = frame().page()) {
973 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
974 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
975 return scrollingCoordinator->isScrollSnapInProgress();
979 // If the main thread updates the scroll position for this FrameView, we should return
980 // ScrollAnimator::isScrollSnapInProgress().
981 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
982 return scrollAnimator->isScrollSnapInProgress();
987 void FrameView::updateScrollingCoordinatorScrollSnapProperties() const
989 renderView()->compositor().updateScrollSnapPropertiesWithFrameView(*this);
993 bool FrameView::flushCompositingStateForThisFrame(const Frame& rootFrameForFlush)
995 RenderView* renderView = this->renderView();
997 return true; // We don't want to keep trying to update layers if we have no renderer.
999 ASSERT(frame().view() == this);
1001 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
1002 // layer content to occur before layout has happened, which will cause paintContents() to bail.
1007 if (LegacyTileCache* tileCache = legacyTileCache())
1008 tileCache->doPendingRepaints();
1011 renderView->compositor().flushPendingLayerChanges(&rootFrameForFlush == m_frame.ptr());
1015 void FrameView::setNeedsOneShotDrawingSynchronization()
1017 if (Page* page = frame().page())
1018 page->chrome().client().setNeedsOneShotDrawingSynchronization();
1021 GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
1023 // To find the Widget that corresponds with platformWidget we have to do a linear
1024 // search of our child widgets.
1025 Widget* foundWidget = nullptr;
1026 for (auto& widget : children()) {
1027 if (widget->platformWidget() != platformWidget)
1029 foundWidget = widget.get();
1036 auto* renderWidget = RenderWidget::find(foundWidget);
1040 RenderLayer* widgetLayer = renderWidget->layer();
1041 if (!widgetLayer || !widgetLayer->isComposited())
1044 return widgetLayer->backing()->parentForSublayers();
1047 void FrameView::scheduleLayerFlushAllowingThrottling()
1049 RenderView* view = this->renderView();
1052 view->compositor().scheduleLayerFlush(true /* canThrottle */);
1055 LayoutRect FrameView::fixedScrollableAreaBoundsInflatedForScrolling(const LayoutRect& uninflatedBounds) const
1057 LayoutPoint scrollPosition = scrollPositionRespectingCustomFixedPosition();
1059 LayoutSize topLeftExpansion = scrollPosition - minimumScrollPosition();
1060 LayoutSize bottomRightExpansion = maximumScrollPosition() - scrollPosition;
1062 return LayoutRect(uninflatedBounds.location() - topLeftExpansion, uninflatedBounds.size() + topLeftExpansion + bottomRightExpansion);
1065 LayoutPoint FrameView::scrollPositionRespectingCustomFixedPosition() const
1068 return useCustomFixedPositionLayoutRect() ? customFixedPositionLayoutRect().location() : scrollPosition();
1070 return scrollPositionForFixedPosition();
1074 void FrameView::setHeaderHeight(int headerHeight)
1077 ASSERT(frame().isMainFrame());
1078 m_headerHeight = headerHeight;
1080 if (RenderView* renderView = this->renderView())
1081 renderView->setNeedsLayout();
1084 void FrameView::setFooterHeight(int footerHeight)
1087 ASSERT(frame().isMainFrame());
1088 m_footerHeight = footerHeight;
1090 if (RenderView* renderView = this->renderView())
1091 renderView->setNeedsLayout();
1094 float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const
1096 if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset)
1097 return platformTopContentInset();
1099 if (!frame().isMainFrame())
1102 Page* page = frame().page();
1103 return page ? page->topContentInset() : 0;
1106 void FrameView::topContentInsetDidChange(float newTopContentInset)
1108 RenderView* renderView = this->renderView();
1112 if (platformWidget())
1113 platformSetTopContentInset(newTopContentInset);
1117 updateScrollbars(scrollPosition());
1118 if (renderView->usesCompositing())
1119 renderView->compositor().frameViewDidChangeSize();
1121 if (TiledBacking* tiledBacking = this->tiledBacking())
1122 tiledBacking->setTopContentInset(newTopContentInset);
1125 bool FrameView::hasCompositedContent() const
1127 if (RenderView* renderView = this->renderView())
1128 return renderView->compositor().inCompositingMode();
1132 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
1133 void FrameView::enterCompositingMode()
1135 if (RenderView* renderView = this->renderView()) {
1136 renderView->compositor().enableCompositingMode();
1138 renderView->compositor().scheduleCompositingLayerUpdate();
1142 bool FrameView::isEnclosedInCompositingLayer() const
1144 auto frameOwnerRenderer = frame().ownerRenderer();
1145 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1148 if (FrameView* parentView = parentFrameView())
1149 return parentView->isEnclosedInCompositingLayer();
1153 bool FrameView::flushCompositingStateIncludingSubframes()
1155 InspectorInstrumentation::willComposite(frame());
1157 bool allFramesFlushed = flushCompositingStateForThisFrame(frame());
1159 for (Frame* child = frame().tree().firstRenderedChild(); child; child = child->tree().traverseNextRendered(m_frame.ptr())) {
1162 bool flushed = child->view()->flushCompositingStateForThisFrame(frame());
1163 allFramesFlushed &= flushed;
1165 return allFramesFlushed;
1168 bool FrameView::isSoftwareRenderable() const
1170 RenderView* renderView = this->renderView();
1171 return !renderView || !renderView->compositor().has3DContent();
1174 void FrameView::setIsInWindow(bool isInWindow)
1176 if (RenderView* renderView = this->renderView())
1177 renderView->setIsInWindow(isInWindow);
1180 inline void FrameView::forceLayoutParentViewIfNeeded()
1182 RenderWidget* ownerRenderer = frame().ownerRenderer();
1186 RenderBox* contentBox = embeddedContentBox();
1190 auto& svgRoot = downcast<RenderSVGRoot>(*contentBox);
1191 if (svgRoot.everHadLayout() && !svgRoot.needsLayout())
1194 LOG(Layout, "FrameView %p forceLayoutParentViewIfNeeded scheduling layout on parent FrameView %p", this, &ownerRenderer->view().frameView());
1196 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1197 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1198 // embeddedContentBox() returns nullptr, as long as the embedded document isn't loaded yet. Before
1199 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1200 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1201 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1202 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1204 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1205 ownerRenderer->view().frameView().scheduleRelayout();
1208 void FrameView::layout(bool allowSubtree)
1210 LOG(Layout, "FrameView %p (%dx%d) layout, main frameview %d, allowSubtree=%d", this, size().width(), size().height(), frame().isMainFrame(), allowSubtree);
1211 if (isInRenderTreeLayout()) {
1212 LOG(Layout, " in layout, bailing");
1216 if (layoutDisallowed()) {
1217 LOG(Layout, " layout is disallowed, bailing");
1221 // Protect the view from being deleted during layout (in recalcStyle).
1222 Ref<FrameView> protect(*this);
1224 // Many of the tasks performed during layout can cause this function to be re-entered,
1225 // so save the layout phase now and restore it on exit.
1226 TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1228 // Every scroll that happens during layout is programmatic.
1229 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1231 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1233 if (inChildFrameLayoutWithFrameFlattening) {
1234 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1235 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1236 if (!root || !root->needsLayout())
1240 TraceScope tracingScope(LayoutStart, LayoutEnd);
1243 if (updateFixedPositionLayoutRect())
1244 allowSubtree = false;
1247 m_layoutTimer.stop();
1248 m_delayedLayout = false;
1249 m_setNeedsLayoutWasDeferred = false;
1251 // we shouldn't enter layout() while painting
1252 ASSERT(!isPainting());
1256 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(frame());
1257 AnimationUpdateBlock animationUpdateBlock(&frame().animation());
1259 if (!allowSubtree && m_layoutRoot)
1260 convertSubtreeLayoutToFullLayout();
1262 ASSERT(frame().view() == this);
1263 ASSERT(frame().document());
1265 Document& document = *frame().document();
1266 ASSERT(!document.inPageCache());
1269 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1271 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1272 // This is a new top-level layout. If there are any remaining tasks from the previous
1273 // layout, finish them now.
1274 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1275 performPostLayoutTasks();
1278 m_layoutPhase = InPreLayoutStyleUpdate;
1280 // Viewport-dependent media queries may cause us to need completely different style information.
1281 StyleResolver* styleResolver = document.styleResolverIfExists();
1282 if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) {
1283 LOG(Layout, " hasMediaQueriesAffectedByViewportChange, enqueueing style recalc");
1284 document.styleResolverChanged(DeferRecalcStyle);
1285 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1286 InspectorInstrumentation::mediaQueryResultChanged(document);
1288 document.evaluateMediaQueryList();
1290 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1291 // take care of that now.
1292 applyPaginationToViewport();
1294 // Always ensure our style info is up-to-date. This can happen in situations where
1295 // the layout beats any sort of style recalc update that needs to occur.
1296 document.updateStyleIfNeeded();
1297 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1298 // so there's no point to continuing to layout
1302 // Close block here so we can set up the font cache purge preventer, which we will still
1303 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1304 // The next block sets m_layoutSchedulingEnabled back to false once again.
1307 m_layoutPhase = InPreLayout;
1309 RenderLayer* layer = nullptr;
1310 bool subtree = false;
1311 RenderElement* root = nullptr;
1313 ++m_nestedLayoutCount;
1316 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1318 autoSizeIfEnabled();
1320 root = m_layoutRoot ? m_layoutRoot : document.renderView();
1323 subtree = m_layoutRoot;
1325 if (!m_layoutRoot) {
1326 auto* body = document.bodyOrFrameset();
1327 if (body && body->renderer()) {
1328 if (is<HTMLFrameSetElement>(*body) && !frameFlatteningEnabled()) {
1329 body->renderer()->setChildNeedsLayout();
1330 } else if (is<HTMLBodyElement>(*body)) {
1331 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport())
1332 body->renderer()->setChildNeedsLayout();
1336 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1337 if (m_firstLayout && !frame().ownerElement())
1338 printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count());
1342 m_needsFullRepaint = !subtree && (m_firstLayout || downcast<RenderView>(*root).printing());
1345 ScrollbarMode hMode;
1346 ScrollbarMode vMode;
1347 calculateScrollbarModesForLayout(hMode, vMode);
1349 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1350 if (m_firstLayout) {
1351 setScrollbarsSuppressed(true);
1353 m_firstLayout = false;
1354 m_firstLayoutCallbackPending = true;
1355 m_lastViewportSize = sizeForResizeEvent();
1356 m_lastZoomFactor = root->style().zoom();
1358 // Set the initial vMode to AlwaysOn if we're auto.
1359 if (vMode == ScrollbarAuto)
1360 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1361 // Set the initial hMode to AlwaysOff if we're auto.
1362 if (hMode == ScrollbarAuto)
1363 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1364 Page* page = frame().page();
1365 if (page && page->expectsWheelEventTriggers())
1366 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
1367 setScrollbarModes(hMode, vMode);
1368 setScrollbarsSuppressed(false, true);
1370 setScrollbarModes(hMode, vMode);
1373 LayoutSize oldSize = m_size;
1374 m_size = layoutSize();
1376 if (oldSize != m_size) {
1377 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());
1378 m_needsFullRepaint = true;
1379 if (!m_firstLayout) {
1380 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : nullptr;
1381 auto* body = document.bodyOrFrameset();
1382 RenderBox* bodyRenderer = rootRenderer && body ? body->renderBox() : nullptr;
1383 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1384 bodyRenderer->setChildNeedsLayout();
1385 else if (rootRenderer && rootRenderer->stretchesToViewport())
1386 rootRenderer->setChildNeedsLayout();
1390 m_layoutPhase = InPreLayout;
1393 layer = root->enclosingLayer();
1394 SubtreeLayoutStateMaintainer subtreeLayoutStateMaintainer(m_layoutRoot);
1396 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1398 ASSERT(m_layoutPhase == InPreLayout);
1399 m_layoutPhase = InRenderTreeLayout;
1401 forceLayoutParentViewIfNeeded();
1403 ASSERT(m_layoutPhase == InRenderTreeLayout);
1406 #if ENABLE(IOS_TEXT_AUTOSIZING)
1407 if (Page* page = frame().page()) {
1408 float minimumZoomFontSize = frame().settings().minimumZoomFontSize();
1409 float textAutosizingWidth = page->textAutosizingWidth();
1410 if (minimumZoomFontSize && textAutosizingWidth && !root->view().printing()) {
1411 root->adjustComputedFontSizesOnBlocks(minimumZoomFontSize, textAutosizingWidth);
1412 if (root->needsLayout())
1417 #if ENABLE(TEXT_AUTOSIZING)
1418 if (document.textAutosizer()->processSubtree(root) && root->needsLayout())
1422 ASSERT(m_layoutPhase == InRenderTreeLayout);
1423 m_layoutRoot = nullptr;
1424 // Close block here to end the scope of changeSchedulingEnabled and SubtreeLayoutStateMaintainer.
1427 m_layoutPhase = InViewSizeAdjust;
1429 bool neededFullRepaint = m_needsFullRepaint;
1431 if (!subtree && !downcast<RenderView>(*root).printing())
1434 m_layoutPhase = InPostLayout;
1436 m_needsFullRepaint = neededFullRepaint;
1438 // Now update the positions of all layers.
1439 if (m_needsFullRepaint)
1440 root->view().repaintRootContents();
1442 root->view().releaseProtectedRenderWidgets();
1444 ASSERT(!root->needsLayout());
1446 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1448 updateCompositingLayersAfterLayout();
1450 m_layoutPhase = InPostLayerPositionsUpdatedAfterLayout;
1454 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1455 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1456 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1459 #if ENABLE(DASHBOARD_SUPPORT)
1460 updateAnnotatedRegions();
1463 #if ENABLE(IOS_TOUCH_EVENTS)
1464 document.dirtyTouchEventRects();
1467 updateCanBlitOnScrollRecursively();
1469 handleDeferredScrollUpdateAfterContentSizeChange();
1471 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1472 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1474 frame().document()->markers().invalidateRectsForAllMarkers();
1476 if (!m_postLayoutTasksTimer.isActive()) {
1477 if (!m_inSynchronousPostLayout) {
1478 if (inChildFrameLayoutWithFrameFlattening)
1479 updateWidgetPositions();
1481 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1482 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1486 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1487 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1488 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1489 // can make us need to update again, and we can get stuck in a nasty cycle unless
1490 // we call it through the timer here.
1491 m_postLayoutTasksTimer.startOneShot(0);
1497 InspectorInstrumentation::didLayout(cookie, root);
1498 DebugPageOverlays::didLayout(frame());
1500 --m_nestedLayoutCount;
1503 bool FrameView::shouldDeferScrollUpdateAfterContentSizeChange()
1505 return (m_layoutPhase < InPostLayout) && (m_layoutPhase != OutsideLayout);
1508 RenderBox* FrameView::embeddedContentBox() const
1510 RenderView* renderView = this->renderView();
1514 RenderObject* firstChild = renderView->firstChild();
1516 // Curently only embedded SVG documents participate in the size-negotiation logic.
1517 if (is<RenderSVGRoot>(firstChild))
1518 return downcast<RenderSVGRoot>(firstChild);
1523 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1525 if (!m_embeddedObjectsToUpdate)
1526 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1528 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1529 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
1530 // Tell the DOM element that it needs a widget update.
1531 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
1532 if (!pluginElement.needsCheckForSizeChange())
1533 pluginElement.setNeedsWidgetUpdate(true);
1536 m_embeddedObjectsToUpdate->add(&embeddedObject);
1539 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1541 if (!m_embeddedObjectsToUpdate)
1544 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1547 void FrameView::setMediaType(const String& mediaType)
1549 m_mediaType = mediaType;
1552 String FrameView::mediaType() const
1554 // See if we have an override type.
1555 String overrideType = frame().loader().client().overrideMediaType();
1556 InspectorInstrumentation::applyEmulatedMedia(frame(), overrideType);
1557 if (!overrideType.isNull())
1558 return overrideType;
1562 void FrameView::adjustMediaTypeForPrinting(bool printing)
1565 if (m_mediaTypeWhenNotPrinting.isNull())
1566 m_mediaTypeWhenNotPrinting = mediaType();
1567 setMediaType("print");
1569 if (!m_mediaTypeWhenNotPrinting.isNull())
1570 setMediaType(m_mediaTypeWhenNotPrinting);
1571 m_mediaTypeWhenNotPrinting = String();
1575 bool FrameView::useSlowRepaints(bool considerOverlap) const
1577 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1579 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1580 // m_contentIsOpaque, so don't take the fast path for composited layers
1581 // if they are a platform widget in order to get painting correctness
1582 // for transparent layers. See the comment in WidgetMac::paint.
1583 if (usesCompositedScrolling() && !platformWidget())
1586 bool isOverlapped = m_isOverlapped && considerOverlap;
1588 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1591 if (FrameView* parentView = parentFrameView())
1592 return parentView->useSlowRepaints(considerOverlap);
1597 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1599 return useSlowRepaints(false);
1602 void FrameView::updateCanBlitOnScrollRecursively()
1604 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
1605 if (FrameView* view = frame->view())
1606 view->setCanBlitOnScroll(!view->useSlowRepaints());
1610 bool FrameView::usesCompositedScrolling() const
1612 RenderView* renderView = this->renderView();
1613 if (renderView && renderView->isComposited()) {
1614 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1615 if (layer && layer->drawsContent())
1622 bool FrameView::usesAsyncScrolling() const
1624 #if ENABLE(ASYNC_SCROLLING)
1625 if (Page* page = frame().page()) {
1626 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1627 return scrollingCoordinator->coordinatesScrollingForFrameView(*this);
1633 bool FrameView::usesMockScrollAnimator() const
1635 return Settings::usesMockScrollAnimator();
1638 void FrameView::logMockScrollAnimatorMessage(const String& message) const
1640 Document* document = frame().document();
1643 StringBuilder builder;
1644 if (frame().isMainFrame())
1645 builder.appendLiteral("Main");
1646 builder.appendLiteral("FrameView: ");
1647 builder.append(message);
1648 document->addConsoleMessage(MessageSource::Other, MessageLevel::Debug, builder.toString());
1651 void FrameView::setCannotBlitToWindow()
1653 m_cannotBlitToWindow = true;
1654 updateCanBlitOnScrollRecursively();
1657 void FrameView::addSlowRepaintObject(RenderElement* o)
1659 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1661 if (!m_slowRepaintObjects)
1662 m_slowRepaintObjects = std::make_unique<HashSet<const RenderElement*>>();
1664 m_slowRepaintObjects->add(o);
1666 if (!hadSlowRepaintObjects) {
1667 updateCanBlitOnScrollRecursively();
1669 if (Page* page = frame().page()) {
1670 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1671 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(*this);
1676 void FrameView::removeSlowRepaintObject(RenderElement* o)
1678 if (!m_slowRepaintObjects)
1681 m_slowRepaintObjects->remove(o);
1682 if (m_slowRepaintObjects->isEmpty()) {
1683 m_slowRepaintObjects = nullptr;
1684 updateCanBlitOnScrollRecursively();
1686 if (Page* page = frame().page()) {
1687 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1688 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(*this);
1693 void FrameView::addViewportConstrainedObject(RenderElement* object)
1695 if (!m_viewportConstrainedObjects)
1696 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1698 if (!m_viewportConstrainedObjects->contains(object)) {
1699 m_viewportConstrainedObjects->add(object);
1700 if (platformWidget())
1701 updateCanBlitOnScrollRecursively();
1703 if (Page* page = frame().page()) {
1704 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1705 scrollingCoordinator->frameViewFixedObjectsDidChange(*this);
1710 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1712 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1713 if (Page* page = frame().page()) {
1714 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1715 scrollingCoordinator->frameViewFixedObjectsDidChange(*this);
1718 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1719 // why isn't the same check being made here?
1720 updateCanBlitOnScrollRecursively();
1724 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1727 if (useCustomFixedPositionLayoutRect())
1728 return customFixedPositionLayoutRect();
1730 LayoutRect viewportRect = visibleContentRect();
1732 viewportRect.setLocation(scrollPositionForFixedPosition());
1733 return viewportRect;
1736 float FrameView::frameScaleFactor() const
1738 return frame().frameScaleFactor();
1741 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)
1743 LayoutPoint position;
1744 if (behaviorForFixed == StickToDocumentBounds)
1745 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1747 position = scrollPosition;
1748 position.setY(position.y() - headerHeight);
1751 LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
1753 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1754 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1756 return LayoutPoint(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1759 float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset)
1761 if (!topContentInset)
1764 // The insetClipLayer should not move for negative scroll values.
1765 float scrollY = std::max<float>(0, scrollPosition.y());
1767 if (scrollY >= topContentInset)
1770 return topContentInset - scrollY;
1773 float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset)
1775 if (!topContentInset)
1778 float scrollY = std::max<float>(0, scrollPosition.y());
1780 if (scrollY >= topContentInset)
1781 return topContentInset;
1786 float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight)
1788 return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight;
1791 FloatPoint FrameView::positionForRootContentLayer(const FloatPoint& scrollPosition, const FloatPoint& scrollOrigin, float topContentInset, float headerHeight)
1793 return FloatPoint(0, yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight) - toFloatSize(scrollOrigin);
1796 FloatPoint FrameView::positionForRootContentLayer() const
1798 return positionForRootContentLayer(scrollPosition(), scrollOrigin(), topContentInset(), headerHeight());
1802 LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
1804 if (fixedElementsLayoutRelativeToFrame)
1805 return visibleContentRect;
1807 if (totalContentsSize.isEmpty())
1808 return visibleContentRect;
1810 // We impose an lower limit on the size (so an upper limit on the scale) of
1811 // the rect used to position fixed objects so that they don't crowd into the
1812 // center of the screen at larger scales.
1813 const LayoutUnit maxContentWidthForZoomThreshold = LayoutUnit::fromPixel(1024);
1814 float zoomedOutScale = frameScaleFactor * visibleContentRect.width() / std::min(maxContentWidthForZoomThreshold, totalContentsSize.width());
1815 float constraintThresholdScale = 1.5 * zoomedOutScale;
1816 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
1818 LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
1820 if (frameScaleFactor > constraintThresholdScale) {
1821 FloatRect contentRect(FloatPoint(), totalContentsSize);
1822 FloatRect viewportRect = visibleContentRect;
1824 // Scale the rect up from a point that is relative to its position in the viewport.
1825 FloatSize sizeDelta = contentRect.size() - viewportRect.size();
1827 FloatPoint scaleOrigin;
1828 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
1829 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
1831 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
1832 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
1833 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
1835 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
1838 if (scrollBehavior == StickToDocumentBounds) {
1839 LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
1840 viewportConstrainedObjectsRect.intersect(documentBounds);
1843 return viewportConstrainedObjectsRect;
1846 LayoutRect FrameView::viewportConstrainedObjectsRect() const
1848 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
1852 ScrollPosition FrameView::minimumScrollPosition() const
1854 ScrollPosition minimumPosition = ScrollView::minimumScrollPosition();
1856 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
1857 minimumPosition.setY(maximumScrollPosition().y());
1859 return minimumPosition;
1862 ScrollPosition FrameView::maximumScrollPosition() const
1864 ScrollPosition maximumPosition = ScrollView::maximumScrollPosition();
1866 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
1867 maximumPosition.setY(minimumScrollPosition().y());
1869 return maximumPosition;
1872 void FrameView::viewportContentsChanged()
1874 if (!frame().view()) {
1875 // The frame is being destroyed.
1879 // When the viewport contents changes (scroll, resize, style recalc, layout, ...),
1880 // check if we should resume animated images or unthrottle DOM timers.
1881 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) {
1882 frameView.resumeVisibleImageAnimations(visibleRect);
1883 frameView.updateScriptedAnimationsAndTimersThrottlingState(visibleRect);
1885 if (auto* renderView = frameView.frame().contentRenderer())
1886 renderView->updateVisibleViewportRect(visibleRect);
1890 bool FrameView::fixedElementsLayoutRelativeToFrame() const
1892 return frame().settings().fixedElementsLayoutRelativeToFrame();
1895 IntPoint FrameView::lastKnownMousePosition() const
1897 return frame().eventHandler().lastKnownMousePosition();
1900 bool FrameView::isHandlingWheelEvent() const
1902 return frame().eventHandler().isHandlingWheelEvent();
1905 bool FrameView::shouldSetCursor() const
1907 Page* page = frame().page();
1908 return page && page->isVisible() && page->focusController().isActive();
1911 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1913 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1914 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1918 const bool isCompositedContentLayer = usesCompositedScrolling();
1920 // Get the rects of the fixed objects visible in the rectToScroll
1921 Region regionToUpdate;
1922 for (auto& renderer : *m_viewportConstrainedObjects) {
1923 if (!renderer->style().hasViewportConstrainedPosition())
1925 if (renderer->isComposited())
1928 // Fixed items should always have layers.
1929 ASSERT(renderer->hasLayer());
1930 RenderLayer* layer = downcast<RenderBoxModelObject>(*renderer).layer();
1932 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1933 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1934 // Don't invalidate for invisible fixed layers.
1938 if (layer->hasAncestorWithFilterOutsets()) {
1939 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1940 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1944 // FIXME: use pixel snapping instead of enclosing when ScrollView has finished transitioning from IntRect to Float/LayoutRect.
1945 IntRect updateRect = enclosingIntRect(layer->repaintRectIncludingNonCompositingDescendants());
1946 updateRect = contentsToRootView(updateRect);
1947 if (!isCompositedContentLayer && clipsRepaints())
1948 updateRect.intersect(rectToScroll);
1949 if (!updateRect.isEmpty())
1950 regionToUpdate.unite(updateRect);
1954 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1956 // 2) update the area of fixed objects that has been invalidated
1957 for (auto& updateRect : regionToUpdate.rects()) {
1958 IntRect scrolledRect = updateRect;
1959 scrolledRect.move(scrollDelta);
1960 updateRect.unite(scrolledRect);
1961 if (isCompositedContentLayer) {
1962 updateRect = rootViewToContents(updateRect);
1963 ASSERT(renderView());
1964 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1967 if (clipsRepaints())
1968 updateRect.intersect(rectToScroll);
1969 hostWindow()->invalidateContentsAndRootView(updateRect);
1975 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1977 repaintSlowRepaintObjects();
1979 if (!usesCompositedScrolling() && isEnclosedInCompositingLayer()) {
1980 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
1981 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), frameRenderer->borderTop() + frameRenderer->paddingTop(),
1982 visibleWidth(), visibleHeight());
1983 frameRenderer->repaintRectangle(rect);
1988 ScrollView::scrollContentsSlowPath(updateRect);
1991 void FrameView::repaintSlowRepaintObjects()
1993 if (!m_slowRepaintObjects)
1996 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
1997 // repaint them after scrolling.
1998 for (auto& renderer : *m_slowRepaintObjects)
1999 renderer->repaintSlowRepaintObject();
2002 // Note that this gets called at painting time.
2003 void FrameView::setIsOverlapped(bool isOverlapped)
2005 if (isOverlapped == m_isOverlapped)
2008 m_isOverlapped = isOverlapped;
2009 updateCanBlitOnScrollRecursively();
2012 bool FrameView::isOverlappedIncludingAncestors() const
2017 if (FrameView* parentView = parentFrameView()) {
2018 if (parentView->isOverlapped())
2025 void FrameView::setContentIsOpaque(bool contentIsOpaque)
2027 if (contentIsOpaque == m_contentIsOpaque)
2030 m_contentIsOpaque = contentIsOpaque;
2031 updateCanBlitOnScrollRecursively();
2034 void FrameView::restoreScrollbar()
2036 setScrollbarsSuppressed(false);
2039 bool FrameView::scrollToFragment(const URL& url)
2041 // If our URL has no ref, then we have no place we need to jump to.
2042 // OTOH If CSS target was set previously, we want to set it to 0, recalc
2043 // and possibly repaint because :target pseudo class may have been
2044 // set (see bug 11321).
2045 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
2048 String fragmentIdentifier = url.fragmentIdentifier();
2049 if (scrollToAnchor(fragmentIdentifier))
2052 // Try again after decoding the ref, based on the document's encoding.
2053 if (TextResourceDecoder* decoder = frame().document()->decoder())
2054 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
2059 bool FrameView::scrollToAnchor(const String& name)
2061 ASSERT(frame().document());
2062 auto& document = *frame().document();
2064 if (!document.haveStylesheetsLoaded()) {
2065 document.setGotoAnchorNeededAfterStylesheetsLoad(true);
2069 document.setGotoAnchorNeededAfterStylesheetsLoad(false);
2071 Element* anchorElement = document.findAnchor(name);
2073 // Setting to null will clear the current target.
2074 document.setCSSTarget(anchorElement);
2076 if (is<SVGDocument>(document)) {
2077 if (auto* rootElement = downcast<SVGDocument>(document).rootElement()) {
2078 rootElement->scrollToAnchor(name, anchorElement);
2084 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2085 if (!anchorElement && !(name.isEmpty() || equalLettersIgnoringASCIICase(name, "top")))
2088 ContainerNode* scrollPositionAnchor = anchorElement;
2089 if (!scrollPositionAnchor)
2090 scrollPositionAnchor = frame().document();
2091 maintainScrollPositionAtAnchor(scrollPositionAnchor);
2093 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
2094 if (anchorElement && anchorElement->isFocusable())
2095 document.setFocusedElement(anchorElement);
2100 void FrameView::maintainScrollPositionAtAnchor(ContainerNode* anchorNode)
2102 m_maintainScrollPositionAnchor = anchorNode;
2103 if (!m_maintainScrollPositionAnchor)
2106 // We need to update the layout before scrolling, otherwise we could
2107 // really mess things up if an anchor scroll comes at a bad moment.
2108 frame().document()->updateStyleIfNeeded();
2109 // Only do a layout if changes have occurred that make it necessary.
2110 RenderView* renderView = this->renderView();
2111 if (renderView && renderView->needsLayout())
2117 void FrameView::scrollElementToRect(const Element& element, const IntRect& rect)
2119 frame().document()->updateLayoutIgnorePendingStylesheets();
2122 if (RenderElement* renderer = element.renderer())
2123 bounds = renderer->anchorRect();
2124 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
2125 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
2126 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
2129 void FrameView::setScrollPosition(const ScrollPosition& scrollPosition)
2131 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
2132 m_maintainScrollPositionAnchor = nullptr;
2133 Page* page = frame().page();
2134 if (page && page->expectsWheelEventTriggers())
2135 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
2136 ScrollView::setScrollPosition(scrollPosition);
2139 void FrameView::contentsResized()
2141 // For non-delegated scrolling, adjustTiledBackingScrollability() is called via addedOrRemovedScrollbar() which occurs less often.
2142 if (delegatesScrolling())
2143 adjustTiledBackingScrollability();
2146 void FrameView::delegatesScrollingDidChange()
2148 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
2149 if (hasCompositedContent())
2150 clearBackingStores();
2153 #if USE(COORDINATED_GRAPHICS)
2154 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
2156 bool visibleContentSizeDidChange = false;
2157 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
2158 // When the viewport size changes or the content is scaled, we need to
2159 // reposition the fixed and sticky positioned elements.
2160 setViewportConstrainedObjectsNeedLayout();
2161 visibleContentSizeDidChange = true;
2164 IntPoint oldPosition = scrollPosition();
2165 ScrollView::setFixedVisibleContentRect(visibleContentRect);
2166 IntPoint newPosition = scrollPosition();
2167 if (oldPosition != newPosition) {
2168 updateLayerPositionsAfterScrolling();
2169 if (frame().settings().acceleratedCompositingForFixedPositionEnabled())
2170 updateCompositingLayersAfterScrolling();
2171 scrollAnimator().setCurrentPosition(newPosition);
2172 scrollPositionChanged(oldPosition, newPosition);
2174 if (visibleContentSizeDidChange) {
2175 // Update the scroll-bars to calculate new page-step size.
2176 updateScrollbars(scrollPosition());
2178 didChangeScrollOffset();
2182 void FrameView::setViewportConstrainedObjectsNeedLayout()
2184 if (!hasViewportConstrainedObjects())
2187 for (auto& renderer : *m_viewportConstrainedObjects)
2188 renderer->setNeedsLayout();
2191 void FrameView::didChangeScrollOffset()
2193 frame().mainFrame().pageOverlayController().didScrollFrame(frame());
2194 frame().loader().client().didChangeScrollOffset();
2197 void FrameView::scrollOffsetChangedViaPlatformWidgetImpl(const ScrollOffset& oldOffset, const ScrollOffset& newOffset)
2199 updateLayerPositionsAfterScrolling();
2200 updateCompositingLayersAfterScrolling();
2201 repaintSlowRepaintObjects();
2202 scrollPositionChanged(scrollPositionFromOffset(oldOffset), scrollPositionFromOffset(newOffset));
2205 void FrameView::scrollPositionChanged(const ScrollPosition& oldPosition, const ScrollPosition& newPosition)
2207 Page* page = frame().page();
2208 auto throttlingDelay = page ? page->chrome().client().eventThrottlingDelay() : std::chrono::milliseconds::zero();
2210 if (throttlingDelay == std::chrono::milliseconds::zero()) {
2211 m_delayedScrollEventTimer.stop();
2213 } else if (!m_delayedScrollEventTimer.isActive())
2214 m_delayedScrollEventTimer.startOneShot(throttlingDelay);
2216 if (Document* document = frame().document())
2217 document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize());
2219 if (RenderView* renderView = this->renderView()) {
2220 if (renderView->usesCompositing())
2221 renderView->compositor().frameViewDidScroll();
2224 viewportContentsChanged();
2227 void FrameView::applyRecursivelyWithVisibleRect(const std::function<void (FrameView& frameView, const IntRect& visibleRect)>& apply)
2229 IntRect windowClipRect = this->windowClipRect();
2230 auto visibleRect = windowToContents(windowClipRect);
2231 apply(*this, visibleRect);
2233 // Recursive call for subframes. We cache the current FrameView's windowClipRect to avoid recomputing it for every subframe.
2234 TemporaryChange<IntRect*> windowClipRectCache(m_cachedWindowClipRect, &windowClipRect);
2235 for (Frame* childFrame = frame().tree().firstChild(); childFrame; childFrame = childFrame->tree().nextSibling()) {
2236 if (auto* childView = childFrame->view())
2237 childView->applyRecursivelyWithVisibleRect(apply);
2241 void FrameView::resumeVisibleImageAnimations(const IntRect& visibleRect)
2243 if (visibleRect.isEmpty())
2246 if (auto* renderView = frame().contentRenderer())
2247 renderView->resumePausedImageAnimationsIfNeeded(visibleRect);
2250 void FrameView::updateScriptedAnimationsAndTimersThrottlingState(const IntRect& visibleRect)
2252 if (frame().isMainFrame())
2255 auto* document = frame().document();
2259 // We don't throttle zero-size or display:none frames because those are usually utility frames.
2260 bool shouldThrottle = visibleRect.isEmpty() && !m_size.isEmpty() && frame().ownerRenderer();
2262 #if ENABLE(REQUEST_ANIMATION_FRAME)
2263 if (auto* scriptedAnimationController = document->scriptedAnimationController())
2264 scriptedAnimationController->setThrottled(shouldThrottle);
2267 document->setTimerThrottlingEnabled(shouldThrottle);
2271 void FrameView::resumeVisibleImageAnimationsIncludingSubframes()
2273 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) {
2274 frameView.resumeVisibleImageAnimations(visibleRect);
2278 void FrameView::updateLayerPositionsAfterScrolling()
2280 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2281 if (m_layoutPhase == InViewSizeAdjust)
2284 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2285 if (RenderView* renderView = this->renderView()) {
2286 updateWidgetPositions();
2287 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2292 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2294 #if ENABLE(ASYNC_SCROLLING)
2295 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2297 Page* page = frame().page();
2301 if (&page->mainFrame() != m_frame.ptr())
2304 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2305 if (!scrollingCoordinator)
2308 if (!scrollingCoordinator->supportsFixedPositionLayers())
2311 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2314 if (inProgrammaticScroll())
2322 void FrameView::updateCompositingLayersAfterScrolling()
2324 ASSERT(m_layoutPhase >= InPostLayout || m_layoutPhase == OutsideLayout);
2326 if (!shouldUpdateCompositingLayersAfterScrolling())
2329 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2330 if (RenderView* renderView = this->renderView())
2331 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2335 bool FrameView::isRubberBandInProgress() const
2337 if (scrollbarsSuppressed())
2340 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2341 // ScrollingCoordinator::isRubberBandInProgress().
2342 if (Page* page = frame().page()) {
2343 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2344 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2345 return scrollingCoordinator->isRubberBandInProgress();
2349 // If the main thread updates the scroll position for this FrameView, we should return
2350 // ScrollAnimator::isRubberBandInProgress().
2351 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2352 return scrollAnimator->isRubberBandInProgress();
2357 bool FrameView::requestScrollPositionUpdate(const ScrollPosition& position)
2359 LOG_WITH_STREAM(Scrolling, stream << "FrameView::requestScrollPositionUpdate " << position);
2361 #if ENABLE(ASYNC_SCROLLING)
2362 if (TiledBacking* tiledBacking = this->tiledBacking())
2363 tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size()));
2366 #if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)
2367 if (Page* page = frame().page()) {
2368 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2369 return scrollingCoordinator->requestScrollPositionUpdate(*this, position);
2372 UNUSED_PARAM(position);
2378 HostWindow* FrameView::hostWindow() const
2380 if (Page* page = frame().page())
2381 return &page->chrome();
2385 void FrameView::addTrackedRepaintRect(const FloatRect& r)
2387 if (!m_isTrackingRepaints || r.isEmpty())
2390 FloatRect repaintRect = r;
2391 repaintRect.moveBy(-scrollPosition());
2392 m_trackedRepaintRects.append(repaintRect);
2395 void FrameView::repaintContentRectangle(const IntRect& r)
2397 ASSERT(!frame().ownerElement());
2399 if (!shouldUpdate())
2402 ScrollView::repaintContentRectangle(r);
2405 static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderElement& renderer, unsigned threshold)
2408 for (const RenderObject* descendant = &renderer; descendant; descendant = descendant->nextInPreOrder()) {
2409 if (is<RenderText>(*descendant)) {
2410 count += downcast<RenderText>(*descendant).text()->length();
2411 if (count >= threshold)
2418 bool FrameView::renderedCharactersExceed(unsigned threshold)
2420 if (!frame().contentRenderer())
2422 return countRenderedCharactersInRenderObjectWithThreshold(*frame().contentRenderer(), threshold) >= threshold;
2425 void FrameView::availableContentSizeChanged(AvailableSizeChangeReason reason)
2427 if (Document* document = frame().document())
2428 document->updateViewportUnitsOnResize();
2431 ScrollView::availableContentSizeChanged(reason);
2434 bool FrameView::shouldLayoutAfterContentsResized() const
2436 return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2439 void FrameView::updateContentsSize()
2441 // We check to make sure the view is attached to a frame() as this method can
2442 // be triggered before the view is attached by Frame::createView(...) setting
2443 // various values such as setScrollBarModes(...) for example. An ASSERT is
2444 // triggered when a view is layout before being attached to a frame().
2445 if (!frame().view())
2449 if (RenderView* root = m_frame->contentRenderer()) {
2450 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2451 setViewportConstrainedObjectsNeedLayout();
2452 // We must eagerly enter compositing mode because fixed position elements
2453 // will not have been made compositing via a preceding style change before
2454 // m_useCustomFixedPositionLayoutRect was true.
2455 root->compositor().enableCompositingMode();
2460 if (shouldLayoutAfterContentsResized() && needsLayout())
2463 if (RenderView* renderView = this->renderView()) {
2464 if (renderView->usesCompositing())
2465 renderView->compositor().frameViewDidChangeSize();
2469 void FrameView::addedOrRemovedScrollbar()
2471 if (RenderView* renderView = this->renderView()) {
2472 if (renderView->usesCompositing())
2473 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2476 adjustTiledBackingScrollability();
2479 void FrameView::adjustTiledBackingScrollability()
2481 auto* tiledBacking = this->tiledBacking();
2485 bool horizontallyScrollable;
2486 bool verticallyScrollable;
2488 if (delegatesScrolling()) {
2489 IntSize documentSize = contentsSize();
2490 IntSize visibleSize = this->visibleSize();
2492 horizontallyScrollable = documentSize.width() > visibleSize.width();
2493 verticallyScrollable = documentSize.height() > visibleSize.height();
2495 horizontallyScrollable = horizontalScrollbar();
2496 verticallyScrollable = verticalScrollbar();
2499 TiledBacking::Scrollability scrollability = TiledBacking::NotScrollable;
2500 if (horizontallyScrollable)
2501 scrollability = TiledBacking::HorizontallyScrollable;
2503 if (verticallyScrollable)
2504 scrollability |= TiledBacking::VerticallyScrollable;
2506 tiledBacking->setScrollability(scrollability);
2510 void FrameView::unobscuredContentSizeChanged()
2512 adjustTiledBackingScrollability();
2516 static LayerFlushThrottleState::Flags determineLayerFlushThrottleState(Page& page)
2518 // We only throttle when constantly receiving new data during the inital page load.
2519 if (!page.progress().isMainLoadProgressing())
2521 // Scrolling during page loading disables throttling.
2522 if (page.mainFrame().view()->wasScrolledByUser())
2524 // Disable for image documents so large GIF animations don't get throttled during loading.
2525 auto* document = page.mainFrame().document();
2526 if (!document || is<ImageDocument>(*document))
2528 return LayerFlushThrottleState::Enabled;
2531 void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2533 if (!frame().page())
2535 auto& page = *frame().page();
2537 LayerFlushThrottleState::Flags flags = LayerFlushThrottleState::UserIsInteracting | determineLayerFlushThrottleState(page);
2538 if (page.chrome().client().adjustLayerFlushThrottling(flags))
2541 if (RenderView* view = renderView())
2542 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2545 void FrameView::loadProgressingStatusChanged()
2547 updateLayerFlushThrottling();
2548 adjustTiledBackingCoverage();
2551 void FrameView::updateLayerFlushThrottling()
2553 Page* page = frame().page();
2557 ASSERT(frame().isMainFrame());
2559 LayerFlushThrottleState::Flags flags = determineLayerFlushThrottleState(*page);
2561 // See if the client is handling throttling.
2562 if (page->chrome().client().adjustLayerFlushThrottling(flags))
2565 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
2566 if (RenderView* renderView = frame->contentRenderer())
2567 renderView->compositor().setLayerFlushThrottlingEnabled(flags & LayerFlushThrottleState::Enabled);
2571 void FrameView::adjustTiledBackingCoverage()
2573 if (!m_speculativeTilingEnabled)
2574 enableSpeculativeTilingIfNeeded();
2576 RenderView* renderView = this->renderView();
2577 if (renderView && renderView->layer()->backing())
2578 renderView->layer()->backing()->adjustTiledBackingCoverage();
2580 if (LegacyTileCache* tileCache = legacyTileCache())
2581 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2585 static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2587 Page* page = view.frame().page();
2588 return page && view.isVisuallyNonEmpty() && !page->progress().isMainLoadProgressing();
2591 void FrameView::enableSpeculativeTilingIfNeeded()
2593 ASSERT(!m_speculativeTilingEnabled);
2594 if (m_wasScrolledByUser) {
2595 m_speculativeTilingEnabled = true;
2598 if (!shouldEnableSpeculativeTilingDuringLoading(*this))
2600 if (m_speculativeTilingEnableTimer.isActive())
2602 // Delay enabling a bit as load completion may trigger further loading from scripts.
2603 static const double speculativeTilingEnableDelay = 0.5;
2604 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
2607 void FrameView::speculativeTilingEnableTimerFired()
2609 if (m_speculativeTilingEnabled)
2611 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
2612 adjustTiledBackingCoverage();
2615 void FrameView::show()
2619 if (frame().isMainFrame()) {
2620 // Turn off speculative tiling for a brief moment after a FrameView appears on screen.
2621 // Note that adjustTiledBackingCoverage() kicks the (500ms) timer to re-enable it.
2622 m_speculativeTilingEnabled = false;
2623 m_wasScrolledByUser = false;
2624 adjustTiledBackingCoverage();
2627 void FrameView::convertSubtreeLayoutToFullLayout()
2629 ASSERT(m_layoutRoot);
2630 m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No);
2631 m_layoutRoot = nullptr;
2634 void FrameView::layoutTimerFired()
2636 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2637 if (!frame().document()->ownerElement())
2638 printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count());
2643 void FrameView::scheduleRelayout()
2645 // FIXME: We should assert the page is not in the page cache, but that is causing
2646 // too many false assertions. See <rdar://problem/7218118>.
2647 ASSERT(frame().view() == this);
2650 convertSubtreeLayoutToFullLayout();
2651 if (!m_layoutSchedulingEnabled)
2655 if (!frame().document()->shouldScheduleLayout())
2657 InspectorInstrumentation::didInvalidateLayout(frame());
2658 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2659 // Also invalidate parent frame starting from the owner element of this frame.
2660 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2661 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2663 std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay();
2664 if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count())
2665 unscheduleRelayout();
2666 if (m_layoutTimer.isActive())
2669 m_delayedLayout = delay.count();
2671 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2672 if (!frame().document()->ownerElement())
2673 printf("Scheduling layout for %d\n", delay);
2676 m_layoutTimer.startOneShot(delay);
2679 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2681 for (RenderObject* r = descendant; r; r = r->container()) {
2688 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2690 ASSERT(renderView());
2691 const RenderView& renderView = *this->renderView();
2693 // Try to catch unnecessary work during render tree teardown.
2694 ASSERT(!renderView.documentBeingDestroyed());
2695 ASSERT(frame().view() == this);
2697 if (renderView.needsLayout()) {
2698 m_layoutRoot = &newRelayoutRoot;
2699 convertSubtreeLayoutToFullLayout();
2703 if (!layoutPending() && m_layoutSchedulingEnabled) {
2704 std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay();
2705 ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout());
2706 m_layoutRoot = &newRelayoutRoot;
2707 InspectorInstrumentation::didInvalidateLayout(frame());
2708 m_delayedLayout = delay.count();
2709 m_layoutTimer.startOneShot(delay);
2713 if (m_layoutRoot == &newRelayoutRoot)
2716 if (!m_layoutRoot) {
2717 // We already have a pending (full) layout. Just mark the subtree for layout.
2718 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
2719 InspectorInstrumentation::didInvalidateLayout(frame());
2723 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2724 // Keep the current root.
2725 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No, m_layoutRoot);
2726 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2730 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2731 // Re-root at newRelayoutRoot.
2732 m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No, &newRelayoutRoot);
2733 m_layoutRoot = &newRelayoutRoot;
2734 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2735 InspectorInstrumentation::didInvalidateLayout(frame());
2738 // Two disjoint subtrees need layout. Mark both of them and issue a full layout instead.
2739 convertSubtreeLayoutToFullLayout();
2740 newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
2741 InspectorInstrumentation::didInvalidateLayout(frame());
2744 bool FrameView::layoutPending() const
2746 return m_layoutTimer.isActive();
2749 bool FrameView::needsStyleRecalcOrLayout(bool includeSubframes) const
2751 if (frame().document() && frame().document()->childNeedsStyleRecalc())
2757 if (!includeSubframes)
2760 for (auto& frameView : renderedChildFrameViews()) {
2761 if (frameView->needsStyleRecalcOrLayout())
2768 bool FrameView::needsLayout() const
2770 // This can return true in cases where the document does not have a body yet.
2771 // Document::shouldScheduleLayout takes care of preventing us from scheduling
2772 // layout in that case.
2773 RenderView* renderView = this->renderView();
2774 return layoutPending()
2775 || (renderView && renderView->needsLayout())
2777 || (m_deferSetNeedsLayoutCount && m_setNeedsLayoutWasDeferred);
2780 void FrameView::setNeedsLayout()
2782 if (m_deferSetNeedsLayoutCount) {
2783 m_setNeedsLayoutWasDeferred = true;
2787 if (RenderView* renderView = this->renderView())
2788 renderView->setNeedsLayout();
2791 void FrameView::unscheduleRelayout()
2793 if (m_postLayoutTasksTimer.isActive())
2794 m_postLayoutTasksTimer.stop();
2796 if (!m_layoutTimer.isActive())
2799 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2800 if (!frame().document()->ownerElement())
2801 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
2804 m_layoutTimer.stop();
2805 m_delayedLayout = false;
2808 #if ENABLE(REQUEST_ANIMATION_FRAME)
2809 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
2811 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext()) {
2812 frame->view()->serviceScrollAnimations();
2813 frame->animation().serviceAnimations();
2816 Vector<RefPtr<Document>> documents;
2817 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext())
2818 documents.append(frame->document());
2820 for (auto& document : documents)
2821 document->serviceScriptedAnimations(monotonicAnimationStartTime);
2825 bool FrameView::isTransparent() const
2827 return m_isTransparent;
2830 void FrameView::setTransparent(bool isTransparent)
2832 if (m_isTransparent == isTransparent)
2835 m_isTransparent = isTransparent;
2837 // setTransparent can be called in the window between FrameView initialization
2838 // and switching in the new Document; this means that the RenderView that we
2839 // retrieve is actually attached to the previous Document, which is going away,
2840 // and must not update compositing layers.
2841 if (!isViewForDocumentInFrame())
2844 renderView()->compositor().rootBackgroundTransparencyChanged();
2847 bool FrameView::hasOpaqueBackground() const
2849 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
2852 Color FrameView::baseBackgroundColor() const
2854 return m_baseBackgroundColor;
2857 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
2859 bool hadAlpha = m_baseBackgroundColor.hasAlpha();
2861 if (!backgroundColor.isValid())
2862 m_baseBackgroundColor = Color::white;
2864 m_baseBackgroundColor = backgroundColor;
2866 if (!isViewForDocumentInFrame())
2869 recalculateScrollbarOverlayStyle();
2871 if (m_baseBackgroundColor.hasAlpha() != hadAlpha)
2872 renderView()->compositor().rootBackgroundTransparencyChanged();
2875 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
2877 for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext(m_frame.ptr())) {
2878 if (FrameView* view = frame->view()) {
2879 view->setTransparent(transparent);
2880 view->setBaseBackgroundColor(backgroundColor);
2885 bool FrameView::hasExtendedBackgroundRectForPainting() const
2887 if (!frame().settings().backgroundShouldExtendBeyondPage())
2890 TiledBacking* tiledBacking = this->tiledBacking();
2894 return tiledBacking->hasMargins();
2897 void FrameView::updateExtendBackgroundIfNecessary()
2899 ExtendedBackgroundMode mode = calculateExtendedBackgroundMode();
2900 if (mode == ExtendedBackgroundModeNone)
2903 updateTilesForExtendedBackgroundMode(mode);
2906 FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
2908 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
2909 // that the background rect needs to be extended for painting. Simple backgrounds can be extended
2910 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
2911 // such as images, require extending the background rect to continue painting into the extended
2912 // region. This function finds out if it is necessary to extend the background rect for painting.
2915 // <rdar://problem/16201373>
2916 return ExtendedBackgroundModeNone;
2918 if (!frame().settings().backgroundShouldExtendBeyondPage())
2919 return ExtendedBackgroundModeNone;
2921 if (!frame().isMainFrame())
2922 return ExtendedBackgroundModeNone;
2924 Document* document = frame().document();
2926 return ExtendedBackgroundModeNone;
2928 auto* documentElement = document->documentElement();
2929 auto* documentElementRenderer = documentElement ? documentElement->renderer() : nullptr;
2930 if (!documentElementRenderer)
2931 return ExtendedBackgroundModeNone;
2933 auto& renderer = documentElementRenderer->rendererForRootBackground();
2934 if (!renderer.style().hasBackgroundImage())
2935 return ExtendedBackgroundModeNone;
2937 ExtendedBackgroundMode mode = ExtendedBackgroundModeNone;
2939 if (renderer.style().backgroundRepeatX() == RepeatFill)
2940 mode |= ExtendedBackgroundModeHorizontal;
2941 if (renderer.style().backgroundRepeatY() == RepeatFill)
2942 mode |= ExtendedBackgroundModeVertical;
2948 void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
2950 if (!frame().settings().backgroundShouldExtendBeyondPage())
2953 RenderView* renderView = this->renderView();
2957 RenderLayerBacking* backing = renderView->layer()->backing();
2961 TiledBacking* tiledBacking = backing->graphicsLayer()->tiledBacking();
2965 ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone;
2966 if (tiledBacking->hasVerticalMargins())
2967 existingMode |= ExtendedBackgroundModeVertical;
2968 if (tiledBacking->hasHorizontalMargins())
2969 existingMode |= ExtendedBackgroundModeHorizontal;
2971 if (existingMode == mode)
2974 renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor());
2975 backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical);
2978 IntRect FrameView::extendedBackgroundRectForPainting() const
2980 TiledBacking* tiledBacking = this->tiledBacking();
2984 RenderView* renderView = this->renderView();
2988 LayoutRect extendedRect = renderView->unextendedBackgroundRect();
2989 if (!tiledBacking->hasMargins())
2990 return snappedIntRect(extendedRect);
2992 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
2993 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
2994 return snappedIntRect(extendedRect);
2997 bool FrameView::shouldUpdateWhileOffscreen() const
2999 return m_shouldUpdateWhileOffscreen;
3002 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
3004 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
3007 bool FrameView::shouldUpdate() const
3009 if (isOffscreen() && !shouldUpdateWhileOffscreen())
3014 void FrameView::scrollToAnchor()
3016 RefPtr<ContainerNode> anchorNode = m_maintainScrollPositionAnchor;
3020 if (!anchorNode->renderer())
3024 if (anchorNode != frame().document() && anchorNode->renderer())
3025 rect = anchorNode->renderer()->anchorRect();
3027 // Scroll nested layers and frames to reveal the anchor.
3028 // Align to the top and to the closest side (this matches other browsers).
3029 if (anchorNode->renderer()->style().isHorizontalWritingMode())
3030 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
3031 else if (anchorNode->renderer()->style().isFlippedBlocksWritingMode())
3032 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
3034 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
3036 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
3037 cache->handleScrolledToAnchor(anchorNode.get());
3039 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
3040 m_maintainScrollPositionAnchor = anchorNode;
3043 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
3045 // No need to update if it's already crashed or known to be missing.
3046 if (embeddedObject.isPluginUnavailable())
3049 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
3051 if (embeddedObject.isSnapshottedPlugIn()) {
3052 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
3053 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
3054 pluginElement.checkSnapshotStatus();
3059 auto weakRenderer = embeddedObject.createWeakPtr();
3061 // FIXME: This could turn into a real virtual dispatch if we defined
3062 // updateWidget(PluginCreationOption) on HTMLElement.
3063 if (is<HTMLPlugInImageElement>(element)) {
3064 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
3065 if (pluginElement.needsCheckForSizeChange()) {
3066 pluginElement.checkSnapshotStatus();
3069 if (pluginElement.needsWidgetUpdate())
3070 pluginElement.updateWidget(CreateAnyWidgetType);
3072 ASSERT_NOT_REACHED();
3074 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
3078 auto ignoreWidgetState = embeddedObject.updateWidgetPosition();
3079 UNUSED_PARAM(ignoreWidgetState);
3082 bool FrameView::updateEmbeddedObjects()
3084 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
3087 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
3089 // Insert a marker for where we should stop.
3090 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
3091 m_embeddedObjectsToUpdate->add(nullptr);
3093 while (!m_embeddedObjectsToUpdate->isEmpty()) {
3094 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
3095 if (!embeddedObject)
3097 updateEmbeddedObject(*embeddedObject);
3100 return m_embeddedObjectsToUpdate->isEmpty();
3103 void FrameView::updateEmbeddedObjectsTimerFired()
3105 RefPtr<FrameView> protect(this);
3106 m_updateEmbeddedObjectsTimer.stop();
3107 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
3108 if (updateEmbeddedObjects())
3113 void FrameView::flushAnyPendingPostLayoutTasks()
3115 if (m_postLayoutTasksTimer.isActive())
3116 performPostLayoutTasks();
3117 if (m_updateEmbeddedObjectsTimer.isActive())
3118 updateEmbeddedObjectsTimerFired();
3121 void FrameView::queuePostLayoutCallback(std::function<void()> callback)
3123 m_postLayoutCallbackQueue.append(callback);
3126 void FrameView::flushPostLayoutTasksQueue()
3128 if (m_nestedLayoutCount > 1)
3131 if (!m_postLayoutCallbackQueue.size())
3134 const auto queue = m_postLayoutCallbackQueue;
3135 m_postLayoutCallbackQueue.clear();
3136 for (size_t i = 0; i < queue.size(); ++i)
3140 void FrameView::performPostLayoutTasks()
3142 LOG(Layout, "FrameView %p performPostLayoutTasks", this);
3144 // FIXME: We should not run any JavaScript code in this function.
3146 m_postLayoutTasksTimer.stop();
3148 frame().selection().updateAppearanceAfterLayout();
3150 flushPostLayoutTasksQueue();
3152 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
3153 fireLayoutRelatedMilestonesIfNeeded();
3156 // Only send layout-related delegate callbacks synchronously for the main frame to
3157 // avoid re-entering layout for the main frame while delivering a layout-related delegate
3158 // callback for a subframe.
3159 if (frame().isMainFrame()) {
3160 if (Page* page = frame().page())
3161 page->chrome().client().didLayout();
3165 #if ENABLE(FONT_LOAD_EVENTS)
3166 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
3167 frame().document()->fonts()->didLayout();
3170 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
3171 // with didLayout(LayoutMilestones).
3172 frame().loader().client().dispatchDidLayout();
3174 updateWidgetPositions();
3176 #if ENABLE(CSS_SCROLL_SNAP)
3177 updateSnapOffsets();
3180 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
3181 // is called through the post layout timer.
3182 Ref<FrameView> protect(*this);
3184 m_updateEmbeddedObjectsTimer.startOneShot(0);
3186 if (auto* page = frame().page()) {
3187 if (auto* scrollingCoordinator = page->scrollingCoordinator())
3188 scrollingCoordinator->frameViewLayoutUpdated(*this);
3191 if (RenderView* renderView = this->renderView()) {
3192 if (renderView->usesCompositing())
3193 renderView->compositor().frameViewDidLayout();
3198 sendResizeEventIfNeeded();
3199 viewportContentsChanged();
3201 updateScrollSnapState();
3204 IntSize FrameView::sizeForResizeEvent() const
3207 if (m_useCustomSizeForResizeEvent)
3208 return m_customSizeForResizeEvent;
3210 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
3211 return fixedLayoutSize();
3212 return visibleContentRectIncludingScrollbars().size();
3215 void FrameView::sendResizeEventIfNeeded()
3217 if (isInRenderTreeLayout() || needsLayout())
3220 RenderView* renderView = this->renderView();
3221 if (!renderView || renderView->printing())
3224 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
3227 IntSize currentSize = sizeForResizeEvent();
3228 float currentZoomFactor = renderView->style().zoom();
3230 if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor)
3233 m_lastViewportSize = currentSize;
3234 m_lastZoomFactor = currentZoomFactor;
3240 // Don't send the resize event if the document is loading. Some pages automatically reload
3241 // when the window is resized; Safari on iOS often resizes the window while setting up its
3242 // viewport. This obviously can cause problems.
3243 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
3244 if (documentLoader->isLoadingInAPISense())
3249 bool isMainFrame = frame().isMainFrame();
3250 bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize;
3252 Ref<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
3253 if (canSendResizeEventSynchronously)
3254 frame().document()->dispatchWindowEvent(resizeEvent);
3256 // FIXME: Queueing this event for an unpredictable time in the future seems
3257 // intrinsically racy. By the time this resize event fires, the frame might
3258 // be resized again, so we could end up with two resize events for the same size.
3259 frame().document()->enqueueWindowEvent(WTFMove(resizeEvent));
3262 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
3263 if (Page* page = frame().page()) {
3264 if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient())
3265 inspectorClient->didResizeMainFrame(&frame());
3270 void FrameView::willStartLiveResize()
3272 ScrollView::willStartLiveResize();
3273 adjustTiledBackingCoverage();
3276 void FrameView::willEndLiveResize()
3278 ScrollView::willEndLiveResize();
3279 adjustTiledBackingCoverage();
3282 void FrameView::autoSizeIfEnabled()
3284 if (!m_shouldAutoSize)
3290 LOG(Layout, "FrameView %p autoSizeIfEnabled", this);
3292 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
3294 Document* document = frame().document();
3298 RenderView* documentView = document->renderView();
3299 Element* documentElement = document->documentElement();
3300 if (!documentView || !documentElement)
3304 convertSubtreeLayoutToFullLayout();
3305 // Start from the minimum size and allow it to grow.
3306 resize(m_minAutoSize.width(), m_minAutoSize.height());
3308 IntSize size = frameRect().size();
3310 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
3311 // which may result in a height change during the second iteration.
3312 for (int i = 0; i < 2; i++) {
3313 // Update various sizes including contentsSize, scrollHeight, etc.
3314 document->updateLayoutIgnorePendingStylesheets();
3315 int width = documentView->minPreferredLogicalWidth();
3316 int height = documentView->documentRect().height();
3317 IntSize newSize(width, height);
3319 // Check to see if a scrollbar is needed for a given dimension and
3320 // if so, increase the other dimension to account for the scrollbar.
3321 // Since the dimensions are only for the view rectangle, once a
3322 // dimension exceeds the maximum, there is no need to increase it further.
3323 if (newSize.width() > m_maxAutoSize.width()) {
3324 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
3325 if (!localHorizontalScrollbar)
3326 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
3327 newSize.expand(0, localHorizontalScrollbar->occupiedHeight());
3329 // Don't bother checking for a vertical scrollbar because the width is at
3330 // already greater the maximum.
3331 } else if (newSize.height() > m_maxAutoSize.height()) {
3332 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
3333 if (!localVerticalScrollbar)
3334 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
3335 newSize.expand(localVerticalScrollbar->occupiedWidth(), 0);
3337 // Don't bother checking for a horizontal scrollbar because the height is
3338 // already greater the maximum.
3341 // Ensure the size is at least the min bounds.
3342 newSize = newSize.expandedTo(m_minAutoSize);
3344 // Bound the dimensions by the max bounds and determine what scrollbars to show.
3345 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
3346 if (newSize.width() > m_maxAutoSize.width()) {
3347 newSize.setWidth(m_maxAutoSize.width());
3348 horizonalScrollbarMode = ScrollbarAlwaysOn;
3350 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
3351 if (newSize.height() > m_maxAutoSize.height()) {
3352 newSize.setHeight(m_maxAutoSize.height());
3353 verticalScrollbarMode = ScrollbarAlwaysOn;
3356 if (newSize == size)
3359 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
3360 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
3361 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
3362 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
3365 // The first time around, resize to the minimum height again; otherwise,
3366 // on pages (e.g. quirks mode) where the body/document resize to the view size,
3367 // we'll end up not shrinking back down after resizing to the computed preferred width.
3368 resize(newSize.width(), i ? newSize.height() : m_minAutoSize.height());
3369 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
3370 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
3371 setVerticalScrollbarLock(false);
3372 setHorizontalScrollbarLock(false);
3373 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
3376 m_autoSizeContentSize = contentsSize();
3378 if (m_autoSizeFixedMinimumHeight) {
3379 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
3380 document->updateLayoutIgnorePendingStylesheets();
3383 m_didRunAutosize = true;
3386 void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
3388 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
3391 m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
3396 RenderElement* FrameView::viewportRenderer() const
3398 if (m_viewportRendererType == ViewportRendererType::None)
3401 auto* document = frame().document();
3405 if (m_viewportRendererType == ViewportRendererType::Document) {
3406 auto* documentElement = document->documentElement();
3407 if (!documentElement)
3409 return documentElement->renderer();
3412 if (m_viewportRendererType == ViewportRendererType::Body) {
3413 auto* body = document->body();
3416 return body->renderer();
3419 ASSERT_NOT_REACHED();
3423 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
3425 auto* viewportRenderer = this->viewportRenderer();
3426 if (!viewportRenderer)
3429 if (m_overflowStatusDirty) {
3430 m_horizontalOverflow = horizontalOverflow;
3431 m_verticalOverflow = verticalOverflow;
3432 m_overflowStatusDirty = false;
3436 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
3437 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
3439 if (horizontalOverflowChanged || verticalOverflowChanged) {
3440 m_horizontalOverflow = horizontalOverflow;
3441 m_verticalOverflow = verticalOverflow;
3443 Ref<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
3444 verticalOverflowChanged, verticalOverflow);
3445 overflowEvent->setTarget(viewportRenderer->element());
3447 frame().document()->enqueueOverflowEvent(WTFMove(overflowEvent));
3451 const Pagination& FrameView::pagination() const
3453 if (m_pagination != Pagination())
3454 return m_pagination;
3456 if (frame().isMainFrame()) {
3457 if (Page* page = frame().page())
3458 return page->pagination();
3461 return m_pagination;
3464 void FrameView::setPagination(const Pagination& pagination)
3466 if (m_pagination == pagination)
3469 m_pagination = pagination;
3471 frame().document()->styleResolverChanged(DeferRecalcStyle);
3474 IntRect FrameView::windowClipRect() const
3476 ASSERT(frame().view() == this);
3478 if (m_cachedWindowClipRect)
3479 return *m_cachedWindowClipRect;
3481 if (paintsEntireContents())
3482 return contentsToWindow(IntRect(IntPoint(), totalContentsSize()));
3484 // Set our clip rect to be our contents.
3485 IntRect clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect));
3487 if (!frame().ownerElement())
3490 // Take our owner element and get its clip rect.
3491 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
3492 if (FrameView* parentView = ownerElement->document().view())
3493 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
3497 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
3499 // The renderer can sometimes be null when style="display:none" interacts
3500 // with external content and plugins.
3501 if (!ownerElement->renderer())
3502 return windowClipRect();
3504 // If we have no layer, just return our window clip rect.
3505 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
3506 if (!enclosingLayer)
3507 return windowClipRect();
3509 // Apply the clip from the layer.
3511 if (clipToLayerContents)
3512 clipRect = snappedIntRect(enclosingLayer->childrenClipRect());
3514 clipRect = snappedIntRect(enclosingLayer->selfClipRect());
3515 clipRect = contentsToWindow(clipRect);
3516 return intersection(clipRect, windowClipRect());
3519 bool FrameView::isActive() const
3521 Page* page = frame().page();
3522 return page && page->focusController().isActive();
3525 bool FrameView::updatesScrollLayerPositionOnMainThread() const
3527 if (Page* page = frame().page()) {
3528 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
3529 return scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously();
3535 bool FrameView::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
3537 Page* page = frame().page();
3538 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
3541 void FrameView::scrollTo(const ScrollPosition& newPosition)
3543 IntPoint oldPosition = scrollPosition();
3544 ScrollView::scrollTo(newPosition);
3545 if (oldPosition != scrollPosition())
3546 scrollPositionChanged(oldPosition, scrollPosition());
3547 didChangeScrollOffset();
3550 float FrameView::adjustScrollStepForFixedContent(float step, ScrollbarOrientation orientation, ScrollGranularity granularity)
3552 if (granularity != ScrollByPage || orientation == HorizontalScrollbar)
3555 TrackedRendererListHashSet* positionedObjects = nullptr;
3556 if (RenderView* root = frame().contentRenderer()) {
3557 if (!root->hasPositionedObjects())
3559 positionedObjects = root->positionedObjects();
3562 FloatRect unobscuredContentRect = this->unobscuredContentRect();
3563 float topObscuredArea = 0;
3564 float bottomObscuredArea = 0;
3565 for (const auto& positionedObject : *positionedObjects) {
3566 const RenderStyle& style = positionedObject->style();
3567 if (style.position() != FixedPosition || style.visibility() == HIDDEN || !style.opacity())
3570 FloatQuad contentQuad = positionedObject->absoluteContentQuad();
3571 if (!contentQuad.isRectilinear())
3574 FloatRect contentBoundingBox = contentQuad.boundingBox();
3575 FloatRect fixedRectInView = intersection(unobscuredContentRect, contentBoundingBox);
3577 if (fixedRectInView.width() < unobscuredContentRect.width())
3580 if (fixedRectInView.y() == unobscuredContentRect.y())
3581 topObscuredArea = std::max(topObscuredArea, fixedRectInView.height());
3582 else if (fixedRectInView.maxY() == unobscuredContentRect.maxY())
3583 bottomObscuredArea = std::max(bottomObscuredArea, fixedRectInView.height());
3586 return Scrollbar::pageStep(unobscuredContentRect.height(), unobscuredContentRect.height() - topObscuredArea - bottomObscuredArea);
3589 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
3591 // Add in our offset within the FrameView.
3592 IntRect dirtyRect = rect;
3593 dirtyRect.moveBy(scrollbar->location());
3594 invalidateRect(dirtyRect);
3597 float FrameView::visibleContentScaleFactor() const
3599 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3602 Page* page = frame().page();
3606 return page->pageScaleFactor();
3609 void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3611 if (!frame().isMainFrame())
3614 Page* page = frame().page();
3618 page->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3621 ScrollableArea* FrameView::enclosingScrollableArea() const
3623 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3627 IntRect FrameView::scrollableAreaBoundingBox(bool*) const
3629 RenderWidget* ownerRenderer = frame().ownerRenderer();
3633 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3636 bool FrameView::isScrollable(Scrollability definitionOfScrollable)
3639 // 1) If there an actual overflow.
3640 // 2) display:none or visibility:hidden set to self or inherited.
3641 // 3) overflow{-x,-y}: hidden;
3642 // 4) scrolling: no;
3644 bool requiresActualOverflowToBeConsideredScrollable = !frame().isMainFrame() || definitionOfScrollable != Scrollability::ScrollableOrRubberbandable;
3645 #if !ENABLE(RUBBER_BANDING)
3646 requiresActualOverflowToBeConsideredScrollable = true;
3650 if (requiresActualOverflowToBeConsideredScrollable) {
3651 IntSize totalContentsSize = this->totalContentsSize();
3652 IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size();
3653 if (totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width())
3658 HTMLFrameOwnerElement* owner = frame().ownerElement();
3659 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3663 ScrollbarMode horizontalMode;
3664 ScrollbarMode verticalMode;
3665 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3666 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3672 bool FrameView::isScrollableOrRubberbandable()
3674 return isScrollable(Scrollability::ScrollableOrRubberbandable);
3677 bool FrameView::hasScrollableOrRubberbandableAncestor()
3679 if (frame().isMainFrame())
3680 return isScrollableOrRubberbandable();
3682 for (FrameView* parent = this->parentFrameView(); parent; parent = parent->parentFrameView()) {
3683 Scrollability frameScrollability = parent->frame().isMainFrame() ? Scrollability::ScrollableOrRubberbandable : Scrollability::Scrollable;
3684 if (parent->isScrollable(frameScrollability))
3691 void FrameView::updateScrollableAreaSet()
3693 // That ensures that only inner frames are cached.
3694 FrameView* parentFrameView = this->parentFrameView();
3695 if (!parentFrameView)
3698 if (!isScrollable()) {
3699 parentFrameView->removeScrollableArea(this);