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 "FontLoader.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameSelection.h"
47 #include "FrameTree.h"
48 #include "GraphicsContext.h"
49 #include "HTMLBodyElement.h"
50 #include "HTMLDocument.h"
51 #include "HTMLFrameElement.h"
52 #include "HTMLFrameSetElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLPlugInImageElement.h"
55 #include "ImageDocument.h"
56 #include "InspectorClient.h"
57 #include "InspectorController.h"
58 #include "InspectorInstrumentation.h"
60 #include "MainFrame.h"
61 #include "MemoryCache.h"
62 #include "MemoryPressureHandler.h"
63 #include "OverflowEvent.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 "ScrollAnimator.h"
84 #include "ScrollingCoordinator.h"
86 #include "StyleResolver.h"
87 #include "TextResourceDecoder.h"
88 #include "TextStream.h"
89 #include "TiledBacking.h"
91 #include <wtf/CurrentTime.h>
93 #include <wtf/TemporaryChange.h>
95 #if USE(TILED_BACKING_STORE)
96 #include "TiledBackingStore.h"
99 #if ENABLE(TEXT_AUTOSIZING)
100 #include "TextAutosizer.h"
103 #if ENABLE(CSS_SCROLL_SNAP)
104 #include "AxisScrollSnapOffsets.h"
108 #include "DocumentLoader.h"
109 #include "LegacyTileCache.h"
110 #include "MemoryCache.h"
111 #include "MemoryPressureHandler.h"
112 #include "SystemMemory.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 FrameView::FrameView(Frame& frame)
165 , m_canHaveScrollbars(true)
166 , m_layoutTimer(*this, &FrameView::layoutTimerFired)
167 , m_layoutRoot(nullptr)
168 , m_layoutPhase(OutsideLayout)
169 , m_inSynchronousPostLayout(false)
170 , m_postLayoutTasksTimer(*this, &FrameView::postLayoutTimerFired)
171 , m_updateEmbeddedObjectsTimer(*this, &FrameView::updateEmbeddedObjectsTimerFired)
172 , m_isTransparent(false)
173 , m_baseBackgroundColor(Color::white)
174 , m_mediaType("screen")
175 , m_overflowStatusDirty(true)
176 , m_viewportRenderer(nullptr)
177 , m_wasScrolledByUser(false)
178 , m_inProgrammaticScroll(false)
179 , m_safeToPropagateScrollToParent(true)
180 , m_delayedScrollEventTimer(*this, &FrameView::delayedScrollEventTimerFired)
181 , m_isTrackingRepaints(false)
182 , m_shouldUpdateWhileOffscreen(true)
183 , m_exposedRect(FloatRect::infiniteRect())
184 , m_deferSetNeedsLayoutCount(0)
185 , m_setNeedsLayoutWasDeferred(false)
186 , m_speculativeTilingEnabled(false)
187 , m_speculativeTilingEnableTimer(*this, &FrameView::speculativeTilingEnableTimerFired)
189 , m_useCustomFixedPositionLayoutRect(false)
190 , m_useCustomSizeForResizeEvent(false)
191 , m_horizontalVelocity(0)
192 , m_verticalVelocity(0)
193 , m_scaleChangeRate(0)
194 , m_lastVelocityUpdateTime(0)
196 , m_hasOverrideViewportSize(false)
197 , m_shouldAutoSize(false)
198 , m_inAutoSize(false)
199 , m_didRunAutosize(false)
200 , m_autoSizeFixedMinimumHeight(0)
203 , m_milestonesPendingPaint(0)
204 , m_visualUpdatesAllowedByClient(true)
205 , m_scrollPinningBehavior(DoNotPin)
209 #if ENABLE(RUBBER_BANDING)
210 ScrollElasticity verticalElasticity = ScrollElasticityNone;
211 ScrollElasticity horizontalElasticity = ScrollElasticityNone;
212 if (m_frame->isMainFrame()) {
213 verticalElasticity = m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed;
214 horizontalElasticity = m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed;
215 } else if (m_frame->settings().rubberBandingForSubScrollableRegionsEnabled()) {
216 verticalElasticity = ScrollElasticityAutomatic;
217 horizontalElasticity = ScrollElasticityAutomatic;
220 ScrollableArea::setVerticalScrollElasticity(verticalElasticity);
221 ScrollableArea::setHorizontalScrollElasticity(horizontalElasticity);
225 Ref<FrameView> FrameView::create(Frame& frame)
227 Ref<FrameView> view = adoptRef(*new FrameView(frame));
232 Ref<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
234 Ref<FrameView> view = adoptRef(*new FrameView(frame));
235 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
240 FrameView::~FrameView()
242 if (m_postLayoutTasksTimer.isActive())
243 m_postLayoutTasksTimer.stop();
245 removeFromAXObjectCache();
248 // Custom scrollbars should already be destroyed at this point
249 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
250 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
252 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
253 setHasVerticalScrollbar(false);
255 ASSERT(!m_scrollCorner);
257 ASSERT(frame().view() != this || !frame().contentRenderer());
260 void FrameView::reset()
262 m_cannotBlitToWindow = false;
263 m_isOverlapped = false;
264 m_contentIsOpaque = false;
265 m_layoutTimer.stop();
266 m_layoutRoot = nullptr;
267 m_delayedLayout = false;
268 m_needsFullRepaint = true;
269 m_layoutSchedulingEnabled = true;
270 m_layoutPhase = OutsideLayout;
271 m_inSynchronousPostLayout = false;
273 m_nestedLayoutCount = 0;
274 m_postLayoutTasksTimer.stop();
275 m_updateEmbeddedObjectsTimer.stop();
276 m_firstLayout = true;
277 m_firstLayoutCallbackPending = false;
278 m_wasScrolledByUser = false;
279 m_safeToPropagateScrollToParent = true;
280 m_delayedScrollEventTimer.stop();
281 m_lastViewportSize = IntSize();
282 m_lastZoomFactor = 1.0f;
283 m_isTrackingRepaints = false;
284 m_trackedRepaintRects.clear();
286 m_paintBehavior = PaintBehaviorNormal;
287 m_isPainting = false;
288 m_visuallyNonEmptyCharacterCount = 0;
289 m_visuallyNonEmptyPixelCount = 0;
290 m_isVisuallyNonEmpty = false;
291 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
292 m_maintainScrollPositionAnchor = nullptr;
293 m_throttledTimers.clear();
296 void FrameView::removeFromAXObjectCache()
298 if (AXObjectCache* cache = axObjectCache()) {
299 if (HTMLFrameOwnerElement* owner = frame().ownerElement())
300 cache->childrenChanged(owner->renderer());
305 void FrameView::resetScrollbars()
307 // Reset the document's scrollbars back to our defaults before we yield the floor.
308 m_firstLayout = true;
309 setScrollbarsSuppressed(true);
310 if (m_canHaveScrollbars)
311 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
313 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
314 setScrollbarsSuppressed(false);
317 void FrameView::resetScrollbarsAndClearContentsSize()
321 setScrollbarsSuppressed(true);
322 setContentsSize(IntSize());
323 setScrollbarsSuppressed(false);
326 void FrameView::init()
330 m_margins = LayoutSize(-1, -1); // undefined
331 m_size = LayoutSize();
333 // Propagate the marginwidth/height and scrolling modes to the view.
334 Element* ownerElement = frame().ownerElement();
335 if (is<HTMLFrameElementBase>(ownerElement)) {
336 HTMLFrameElementBase& frameElement = downcast<HTMLFrameElementBase>(*ownerElement);
337 if (frameElement.scrollingMode() == ScrollbarAlwaysOff)
338 setCanHaveScrollbars(false);
339 LayoutUnit marginWidth = frameElement.marginWidth();
340 LayoutUnit marginHeight = frameElement.marginHeight();
341 if (marginWidth != -1)
342 setMarginWidth(marginWidth);
343 if (marginHeight != -1)
344 setMarginHeight(marginHeight);
347 Page* page = frame().page();
348 if (page && page->chrome().client().shouldPaintEntireContents())
349 setPaintsEntireContents(true);
352 void FrameView::prepareForDetach()
354 detachCustomScrollbars();
355 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
356 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
357 removeFromAXObjectCache();
359 if (frame().page()) {
360 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
361 scrollingCoordinator->willDestroyScrollableArea(this);
365 void FrameView::detachCustomScrollbars()
367 Scrollbar* horizontalBar = horizontalScrollbar();
368 if (horizontalBar && horizontalBar->isCustomScrollbar())
369 setHasHorizontalScrollbar(false);
371 Scrollbar* verticalBar = verticalScrollbar();
372 if (verticalBar && verticalBar->isCustomScrollbar())
373 setHasVerticalScrollbar(false);
375 m_scrollCorner = nullptr;
378 void FrameView::recalculateScrollbarOverlayStyle()
380 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
381 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
383 Color backgroundColor = documentBackgroundColor();
384 if (backgroundColor.isValid()) {
385 // Reduce the background color from RGB to a lightness value
386 // and determine which scrollbar style to use based on a lightness
388 double hue, saturation, lightness;
389 backgroundColor.getHSL(hue, saturation, lightness);
390 if (lightness <= .5 && backgroundColor.alpha() > 0)
391 overlayStyle = ScrollbarOverlayStyleLight;
394 if (oldOverlayStyle != overlayStyle)
395 setScrollbarOverlayStyle(overlayStyle);
398 void FrameView::clear()
400 setCanBlitOnScroll(true);
404 setScrollbarsSuppressed(true);
407 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
408 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
409 if (LegacyTileCache* tileCache = legacyTileCache())
410 tileCache->setTilingMode(LegacyTileCache::Disabled);
414 bool FrameView::didFirstLayout() const
416 return !m_firstLayout;
419 void FrameView::invalidateRect(const IntRect& rect)
422 if (HostWindow* window = hostWindow())
423 window->invalidateContentsAndRootView(rect);
427 RenderWidget* renderer = frame().ownerRenderer();
431 IntRect repaintRect = rect;
432 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
433 renderer->borderTop() + renderer->paddingTop());
434 renderer->repaintRectangle(repaintRect);
437 void FrameView::setFrameRect(const IntRect& newRect)
439 IntRect oldRect = frameRect();
440 if (newRect == oldRect)
443 #if ENABLE(TEXT_AUTOSIZING)
444 // Autosized font sizes depend on the width of the viewing area.
445 if (newRect.width() != oldRect.width()) {
446 if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) {
447 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
448 frame().document()->textAutosizer()->recalculateMultipliers();
453 ScrollView::setFrameRect(newRect);
455 updateScrollableAreaSet();
457 if (RenderView* renderView = this->renderView()) {
458 if (renderView->usesCompositing())
459 renderView->compositor().frameViewDidChangeSize();
462 if (frame().isMainFrame())
463 frame().mainFrame().pageOverlayController().didChangeViewSize();
465 viewportContentsChanged();
468 #if ENABLE(REQUEST_ANIMATION_FRAME)
469 bool FrameView::scheduleAnimation()
471 if (HostWindow* window = hostWindow()) {
472 window->scheduleAnimation();
479 void FrameView::setMarginWidth(LayoutUnit w)
481 // make it update the rendering area when set
482 m_margins.setWidth(w);
485 void FrameView::setMarginHeight(LayoutUnit h)
487 // make it update the rendering area when set
488 m_margins.setHeight(h);
491 bool FrameView::frameFlatteningEnabled() const
493 return frame().settings().frameFlatteningEnabled();
496 bool FrameView::isFrameFlatteningValidForThisFrame() const
498 if (!frameFlatteningEnabled())
501 HTMLFrameOwnerElement* owner = frame().ownerElement();
505 // Frame flattening is valid only for <frame> and <iframe>.
506 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
509 bool FrameView::avoidScrollbarCreation() const
511 // with frame flattening no subframe can have scrollbars
512 // but we also cannot turn scrollbars off as we determine
513 // our flattening policy using that.
514 return isFrameFlatteningValidForThisFrame();
517 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
519 m_canHaveScrollbars = canHaveScrollbars;
520 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
523 void FrameView::updateCanHaveScrollbars()
527 scrollbarModes(hMode, vMode);
528 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
529 setCanHaveScrollbars(false);
531 setCanHaveScrollbars(true);
534 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
536 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
537 return ScrollView::createScrollbar(orientation);
539 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
540 Document* doc = frame().document();
542 // Try the <body> element first as a scrollbar source.
543 HTMLElement* body = doc ? doc->bodyOrFrameset() : nullptr;
544 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
545 return RenderScrollbar::createCustomScrollbar(*this, orientation, body);
547 // If the <body> didn't have a custom style, then the root element might.
548 Element* docElement = doc ? doc->documentElement() : nullptr;
549 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
550 return RenderScrollbar::createCustomScrollbar(*this, orientation, docElement);
552 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
553 RenderWidget* frameRenderer = frame().ownerRenderer();
554 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
555 return RenderScrollbar::createCustomScrollbar(*this, orientation, nullptr, &frame());
557 // Nobody set a custom style, so we just use a native scrollbar.
558 return ScrollView::createScrollbar(orientation);
561 void FrameView::setContentsSize(const IntSize& size)
563 if (size == contentsSize())
566 m_deferSetNeedsLayoutCount++;
568 ScrollView::setContentsSize(size);
571 Page* page = frame().page();
575 updateScrollableAreaSet();
577 page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
579 if (frame().isMainFrame())
580 frame().mainFrame().pageOverlayController().didChangeDocumentSize();
582 ASSERT(m_deferSetNeedsLayoutCount);
583 m_deferSetNeedsLayoutCount--;
585 if (!m_deferSetNeedsLayoutCount)
586 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
589 void FrameView::adjustViewSize()
591 RenderView* renderView = this->renderView();
595 ASSERT(frame().view() == this);
597 const IntRect rect = renderView->documentRect();
598 const IntSize& size = rect.size();
599 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
601 setContentsSize(size);
604 void FrameView::applyOverflowToViewport(RenderElement* renderer, ScrollbarMode& hMode, ScrollbarMode& vMode)
606 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
607 // overflow:hidden and overflow:scroll on <body> as applying to the document's
608 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
609 // use the root element.
611 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
612 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
615 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
617 EOverflow overflowX = renderer->style().overflowX();
618 EOverflow overflowY = renderer->style().overflowY();
620 if (is<RenderSVGRoot>(*renderer)) {
621 // FIXME: evaluate if we can allow overflow for these cases too.
622 // Overflow is always hidden when stand-alone SVG documents are embedded.
623 if (downcast<RenderSVGRoot>(*renderer).isEmbeddedThroughFrameContainingSVGDocument()) {
632 hMode = ScrollbarAuto;
634 hMode = ScrollbarAlwaysOff;
637 hMode = ScrollbarAlwaysOn;
640 hMode = ScrollbarAuto;
643 // Don't set it at all.
650 vMode = ScrollbarAuto;
652 vMode = ScrollbarAlwaysOff;
655 vMode = ScrollbarAlwaysOn;
658 vMode = ScrollbarAuto;
661 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
665 m_viewportRenderer = renderer;
668 void FrameView::applyPaginationToViewport()
670 Document* document = frame().document();
671 auto documentElement = document->documentElement();
672 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
673 RenderElement* documentOrBodyRenderer = documentRenderer;
674 auto* body = document->body();
675 if (body && body->renderer())
676 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(*documentElement) ? body->renderer() : documentRenderer;
678 Pagination pagination;
680 if (!documentOrBodyRenderer) {
681 setPagination(pagination);
685 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
686 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
687 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
688 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
691 setPagination(pagination);
694 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
696 m_viewportRenderer = nullptr;
698 const HTMLFrameOwnerElement* owner = frame().ownerElement();
699 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
700 hMode = ScrollbarAlwaysOff;
701 vMode = ScrollbarAlwaysOff;
705 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
706 hMode = ScrollbarAuto;
707 vMode = ScrollbarAuto;
709 hMode = ScrollbarAlwaysOff;
710 vMode = ScrollbarAlwaysOff;
714 Document* document = frame().document();
715 auto documentElement = document->documentElement();
716 RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr;
717 auto* body = document->bodyOrFrameset();
718 if (body && body->renderer()) {
719 if (is<HTMLFrameSetElement>(*body) && !frameFlatteningEnabled()) {
720 vMode = ScrollbarAlwaysOff;
721 hMode = ScrollbarAlwaysOff;
722 } else if (is<HTMLBodyElement>(*body)) {
723 // It's sufficient to just check the X overflow,
724 // since it's illegal to have visible in only one direction.
725 RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && is<HTMLHtmlElement>(*document->documentElement()) ? body->renderer() : rootRenderer;
726 applyOverflowToViewport(o, hMode, vMode);
728 } else if (rootRenderer)
729 applyOverflowToViewport(rootRenderer, hMode, vMode);
733 void FrameView::updateCompositingLayersAfterStyleChange()
735 RenderView* renderView = this->renderView();
739 // If we expect to update compositing after an incipient layout, don't do so here.
740 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
743 RenderLayerCompositor& compositor = renderView->compositor();
744 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
745 compositor.cacheAcceleratedCompositingFlags();
746 compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange);
749 void FrameView::updateCompositingLayersAfterLayout()
751 RenderView* renderView = this->renderView();
755 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
756 renderView->compositor().cacheAcceleratedCompositingFlags();
757 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
760 void FrameView::clearBackingStores()
762 RenderView* renderView = this->renderView();
766 RenderLayerCompositor& compositor = renderView->compositor();
767 ASSERT(compositor.inCompositingMode());
768 compositor.enableCompositingMode(false);
769 compositor.clearBackingForAllLayers();
772 void FrameView::restoreBackingStores()
774 RenderView* renderView = this->renderView();
778 RenderLayerCompositor& compositor = renderView->compositor();
779 compositor.enableCompositingMode(true);
780 compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
783 GraphicsLayer* FrameView::layerForScrolling() const
785 RenderView* renderView = this->renderView();
788 return renderView->compositor().scrollLayer();
791 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
793 RenderView* renderView = this->renderView();
796 return renderView->compositor().layerForHorizontalScrollbar();
799 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
801 RenderView* renderView = this->renderView();
804 return renderView->compositor().layerForVerticalScrollbar();
807 GraphicsLayer* FrameView::layerForScrollCorner() const
809 RenderView* renderView = this->renderView();
812 return renderView->compositor().layerForScrollCorner();
815 TiledBacking* FrameView::tiledBacking() const
817 RenderView* renderView = this->renderView();
821 RenderLayerBacking* backing = renderView->layer()->backing();
825 return backing->graphicsLayer()->tiledBacking();
828 uint64_t FrameView::scrollLayerID() const
830 RenderView* renderView = this->renderView();
834 RenderLayerBacking* backing = renderView->layer()->backing();
838 return backing->scrollingNodeIDForRole(FrameScrollingNode);
841 ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
843 RenderView* renderView = this->renderView();
847 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
850 #if ENABLE(RUBBER_BANDING)
851 GraphicsLayer* FrameView::layerForOverhangAreas() const
853 RenderView* renderView = this->renderView();
856 return renderView->compositor().layerForOverhangAreas();
859 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
861 RenderView* renderView = this->renderView();
865 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
868 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
870 RenderView* renderView = this->renderView();
874 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
877 #endif // ENABLE(RUBBER_BANDING)
879 #if ENABLE(CSS_SCROLL_SNAP)
880 void FrameView::updateSnapOffsets()
882 if (!frame().document())
885 // FIXME: Should we allow specifying snap points through <html> tags too?
886 HTMLElement* body = frame().document()->bodyOrFrameset();
887 if (!renderView() || !body || !body->renderer())
890 updateSnapOffsetsForScrollableArea(*this, *body, *renderView(), body->renderer()->style());
894 bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush)
896 RenderView* renderView = this->renderView();
898 return true; // We don't want to keep trying to update layers if we have no renderer.
900 ASSERT(frame().view() == this);
902 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
903 // layer content to occur before layout has happened, which will cause paintContents() to bail.
908 if (LegacyTileCache* tileCache = legacyTileCache())
909 tileCache->doPendingRepaints();
912 renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame());
917 void FrameView::setNeedsOneShotDrawingSynchronization()
919 if (Page* page = frame().page())
920 page->chrome().client().setNeedsOneShotDrawingSynchronization();
923 GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
925 // To find the Widget that corresponds with platformWidget we have to do a linear
926 // search of our child widgets.
927 Widget* foundWidget = nullptr;
928 for (auto& widget : children()) {
929 if (widget->platformWidget() != platformWidget)
931 foundWidget = widget.get();
938 auto* renderWidget = RenderWidget::find(foundWidget);
942 RenderLayer* widgetLayer = renderWidget->layer();
943 if (!widgetLayer || !widgetLayer->isComposited())
946 return widgetLayer->backing()->parentForSublayers();
949 void FrameView::scheduleLayerFlushAllowingThrottling()
951 RenderView* view = this->renderView();
954 view->compositor().scheduleLayerFlush(true /* canThrottle */);
957 void FrameView::setHeaderHeight(int headerHeight)
960 ASSERT(frame().isMainFrame());
961 m_headerHeight = headerHeight;
963 if (RenderView* renderView = this->renderView())
964 renderView->setNeedsLayout();
967 void FrameView::setFooterHeight(int footerHeight)
970 ASSERT(frame().isMainFrame());
971 m_footerHeight = footerHeight;
973 if (RenderView* renderView = this->renderView())
974 renderView->setNeedsLayout();
977 float FrameView::topContentInset(TopContentInsetType contentInsetTypeToReturn) const
979 if (platformWidget() && contentInsetTypeToReturn == TopContentInsetType::WebCoreOrPlatformContentInset)
980 return platformTopContentInset();
982 if (!frame().isMainFrame())
985 Page* page = frame().page();
986 return page ? page->topContentInset() : 0;
989 void FrameView::topContentInsetDidChange(float newTopContentInset)
991 RenderView* renderView = this->renderView();
995 if (platformWidget())
996 platformSetTopContentInset(newTopContentInset);
1000 updateScrollbars(scrollOffset());
1001 if (renderView->usesCompositing())
1002 renderView->compositor().frameViewDidChangeSize();
1004 if (TiledBacking* tiledBacking = this->tiledBacking())
1005 tiledBacking->setTopContentInset(newTopContentInset);
1008 bool FrameView::hasCompositedContent() const
1010 if (RenderView* renderView = this->renderView())
1011 return renderView->compositor().inCompositingMode();
1015 bool FrameView::hasCompositedContentIncludingDescendants() const
1017 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1018 RenderView* renderView = frame->contentRenderer();
1019 if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : nullptr) {
1020 if (compositor->inCompositingMode())
1023 if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this))
1030 bool FrameView::hasCompositingAncestor() const
1032 for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) {
1033 if (FrameView* view = frame->view()) {
1034 if (view->hasCompositedContent())
1041 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
1042 void FrameView::enterCompositingMode()
1044 if (RenderView* renderView = this->renderView()) {
1045 renderView->compositor().enableCompositingMode();
1047 renderView->compositor().scheduleCompositingLayerUpdate();
1051 bool FrameView::isEnclosedInCompositingLayer() const
1053 auto frameOwnerRenderer = frame().ownerRenderer();
1054 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1057 if (FrameView* parentView = parentFrameView())
1058 return parentView->isEnclosedInCompositingLayer();
1062 bool FrameView::flushCompositingStateIncludingSubframes()
1064 bool allFramesFlushed = flushCompositingStateForThisFrame(&frame());
1066 for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) {
1067 bool flushed = child->view()->flushCompositingStateForThisFrame(&frame());
1068 allFramesFlushed &= flushed;
1070 return allFramesFlushed;
1073 bool FrameView::isSoftwareRenderable() const
1075 RenderView* renderView = this->renderView();
1076 return !renderView || !renderView->compositor().has3DContent();
1079 void FrameView::setIsInWindow(bool isInWindow)
1081 if (RenderView* renderView = this->renderView())
1082 renderView->setIsInWindow(isInWindow);
1085 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
1087 return onlyDuringLayout && layoutPending() ? nullptr : m_layoutRoot;
1090 inline void FrameView::forceLayoutParentViewIfNeeded()
1092 RenderWidget* ownerRenderer = frame().ownerRenderer();
1096 RenderBox* contentBox = embeddedContentBox();
1100 auto& svgRoot = downcast<RenderSVGRoot>(*contentBox);
1101 if (svgRoot.everHadLayout() && !svgRoot.needsLayout())
1104 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1105 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1106 // embeddedContentBox() returns nullptr, as long as the embedded document isn't loaded yet. Before
1107 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1108 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1109 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1110 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1111 Ref<FrameView> frameView(ownerRenderer->view().frameView());
1113 // Mark the owner renderer as needing layout.
1114 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1116 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
1117 frameView->layout();
1120 void FrameView::layout(bool allowSubtree)
1125 // Protect the view from being deleted during layout (in recalcStyle).
1126 Ref<FrameView> protect(*this);
1128 // Many of the tasks performed during layout can cause this function to be re-entered,
1129 // so save the layout phase now and restore it on exit.
1130 TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1132 // Every scroll that happens during layout is programmatic.
1133 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1135 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1137 if (inChildFrameLayoutWithFrameFlattening) {
1138 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1139 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1140 if (!root || !root->needsLayout())
1145 if (updateFixedPositionLayoutRect())
1146 allowSubtree = false;
1149 m_layoutTimer.stop();
1150 m_delayedLayout = false;
1151 m_setNeedsLayoutWasDeferred = false;
1153 // we shouldn't enter layout() while painting
1154 ASSERT(!isPainting());
1158 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(frame());
1159 AnimationUpdateBlock animationUpdateBlock(&frame().animation());
1161 if (!allowSubtree && m_layoutRoot) {
1162 m_layoutRoot->markContainingBlocksForLayout(false);
1163 m_layoutRoot = nullptr;
1166 ASSERT(frame().view() == this);
1167 ASSERT(frame().document());
1169 Document& document = *frame().document();
1170 ASSERT(!document.inPageCache());
1173 RenderElement* root;
1176 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1178 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1179 // This is a new top-level layout. If there are any remaining tasks from the previous
1180 // layout, finish them now.
1181 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1182 performPostLayoutTasks();
1185 m_layoutPhase = InPreLayoutStyleUpdate;
1187 // Viewport-dependent media queries may cause us to need completely different style information.
1188 StyleResolver* styleResolver = document.styleResolverIfExists();
1189 if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) {
1190 document.styleResolverChanged(DeferRecalcStyle);
1191 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1192 InspectorInstrumentation::mediaQueryResultChanged(document);
1194 document.evaluateMediaQueryList();
1196 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1197 // take care of that now.
1198 applyPaginationToViewport();
1200 // Always ensure our style info is up-to-date. This can happen in situations where
1201 // the layout beats any sort of style recalc update that needs to occur.
1202 document.updateStyleIfNeeded();
1203 m_layoutPhase = InPreLayout;
1205 subtree = m_layoutRoot;
1207 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1208 // so there's no point to continuing to layout
1212 root = subtree ? m_layoutRoot : document.renderView();
1214 // FIXME: Do we need to set m_size here?
1218 // Close block here so we can set up the font cache purge preventer, which we will still
1219 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1220 // The next block sets m_layoutSchedulingEnabled back to false once again.
1225 ++m_nestedLayoutCount;
1228 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1230 if (!m_layoutRoot) {
1231 auto* body = document.bodyOrFrameset();
1232 if (body && body->renderer()) {
1233 if (is<HTMLFrameSetElement>(*body) && !frameFlatteningEnabled()) {
1234 body->renderer()->setChildNeedsLayout();
1235 } else if (is<HTMLBodyElement>(*body)) {
1236 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport())
1237 body->renderer()->setChildNeedsLayout();
1241 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1242 if (m_firstLayout && !frame().ownerElement())
1243 printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count());
1247 autoSizeIfEnabled();
1249 m_needsFullRepaint = !subtree && (m_firstLayout || downcast<RenderView>(*root).printing());
1252 ScrollbarMode hMode;
1253 ScrollbarMode vMode;
1254 calculateScrollbarModesForLayout(hMode, vMode);
1256 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1257 if (m_firstLayout) {
1258 setScrollbarsSuppressed(true);
1260 m_firstLayout = false;
1261 m_firstLayoutCallbackPending = true;
1262 m_lastViewportSize = sizeForResizeEvent();
1263 m_lastZoomFactor = root->style().zoom();
1265 // Set the initial vMode to AlwaysOn if we're auto.
1266 if (vMode == ScrollbarAuto)
1267 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1268 // Set the initial hMode to AlwaysOff if we're auto.
1269 if (hMode == ScrollbarAuto)
1270 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1272 setScrollbarModes(hMode, vMode);
1273 setScrollbarsSuppressed(false, true);
1275 setScrollbarModes(hMode, vMode);
1278 LayoutSize oldSize = m_size;
1279 m_size = layoutSize();
1281 if (oldSize != m_size) {
1282 m_needsFullRepaint = true;
1283 if (!m_firstLayout) {
1284 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : nullptr;
1285 auto* body = document.bodyOrFrameset();
1286 RenderBox* bodyRenderer = rootRenderer && body ? body->renderBox() : nullptr;
1287 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1288 bodyRenderer->setChildNeedsLayout();
1289 else if (rootRenderer && rootRenderer->stretchesToViewport())
1290 rootRenderer->setChildNeedsLayout();
1294 m_layoutPhase = InPreLayout;
1297 layer = root->enclosingLayer();
1299 bool disableLayoutState = false;
1301 disableLayoutState = root->view().shouldDisableLayoutStateForSubtree(root);
1302 root->view().pushLayoutState(*root);
1304 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? &root->view() : nullptr);
1305 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1307 ASSERT(m_layoutPhase == InPreLayout);
1308 m_layoutPhase = InLayout;
1310 forceLayoutParentViewIfNeeded();
1312 ASSERT(m_layoutPhase == InLayout);
1315 #if ENABLE(IOS_TEXT_AUTOSIZING)
1316 float minZoomFontSize = frame().settings().minimumZoomFontSize();
1317 float visWidth = frame().page()->textAutosizingWidth();
1318 if (minZoomFontSize && visWidth && !root->view().printing()) {
1319 root->adjustComputedFontSizesOnBlocks(minZoomFontSize, visWidth);
1320 bool needsLayout = root->needsLayout();
1325 #if ENABLE(TEXT_AUTOSIZING)
1326 if (document.textAutosizer()->processSubtree(root) && root->needsLayout())
1330 ASSERT(m_layoutPhase == InLayout);
1333 root->view().popLayoutState(*root);
1335 m_layoutRoot = nullptr;
1337 // Close block here to end the scope of changeSchedulingEnabled and layoutStateDisabler.
1340 m_layoutPhase = InViewSizeAdjust;
1342 bool neededFullRepaint = m_needsFullRepaint;
1344 if (!subtree && !downcast<RenderView>(*root).printing())
1347 m_layoutPhase = InPostLayout;
1349 m_needsFullRepaint = neededFullRepaint;
1351 // Now update the positions of all layers.
1352 if (m_needsFullRepaint)
1353 root->view().repaintRootContents();
1355 ASSERT(!root->needsLayout());
1357 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1359 updateCompositingLayersAfterLayout();
1361 m_layoutPhase = InPostLayerPositionsUpdatedAfterLayout;
1365 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1366 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1367 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1370 #if ENABLE(DASHBOARD_SUPPORT)
1371 updateAnnotatedRegions();
1374 #if ENABLE(IOS_TOUCH_EVENTS)
1375 document.dirtyTouchEventRects();
1378 updateCanBlitOnScrollRecursively();
1380 handleDeferredScrollUpdateAfterContentSizeChange();
1382 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1383 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1385 if (!m_postLayoutTasksTimer.isActive()) {
1386 if (!m_inSynchronousPostLayout) {
1387 if (inChildFrameLayoutWithFrameFlattening)
1388 updateWidgetPositions();
1390 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1391 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1395 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1396 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1397 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1398 // can make us need to update again, and we can get stuck in a nasty cycle unless
1399 // we call it through the timer here.
1400 m_postLayoutTasksTimer.startOneShot(0);
1406 InspectorInstrumentation::didLayout(cookie, root);
1407 if (frame().isMainFrame())
1408 DebugPageOverlays::didLayout(frame().mainFrame());
1410 --m_nestedLayoutCount;
1413 bool FrameView::shouldDeferScrollUpdateAfterContentSizeChange()
1415 return (m_layoutPhase < InPostLayout) && (m_layoutPhase != OutsideLayout);
1418 RenderBox* FrameView::embeddedContentBox() const
1420 RenderView* renderView = this->renderView();
1424 RenderObject* firstChild = renderView->firstChild();
1426 // Curently only embedded SVG documents participate in the size-negotiation logic.
1427 if (is<RenderSVGRoot>(firstChild))
1428 return downcast<RenderSVGRoot>(firstChild);
1433 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1435 if (!m_embeddedObjectsToUpdate)
1436 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1438 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1439 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
1440 // Tell the DOM element that it needs a widget update.
1441 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
1442 if (!pluginElement.needsCheckForSizeChange())
1443 pluginElement.setNeedsWidgetUpdate(true);
1446 m_embeddedObjectsToUpdate->add(&embeddedObject);
1449 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1451 if (!m_embeddedObjectsToUpdate)
1454 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1457 void FrameView::setMediaType(const String& mediaType)
1459 m_mediaType = mediaType;
1462 String FrameView::mediaType() const
1464 // See if we have an override type.
1465 String overrideType = frame().loader().client().overrideMediaType();
1466 InspectorInstrumentation::applyEmulatedMedia(frame(), overrideType);
1467 if (!overrideType.isNull())
1468 return overrideType;
1472 void FrameView::adjustMediaTypeForPrinting(bool printing)
1475 if (m_mediaTypeWhenNotPrinting.isNull())
1476 m_mediaTypeWhenNotPrinting = mediaType();
1477 setMediaType("print");
1479 if (!m_mediaTypeWhenNotPrinting.isNull())
1480 setMediaType(m_mediaTypeWhenNotPrinting);
1481 m_mediaTypeWhenNotPrinting = String();
1485 bool FrameView::useSlowRepaints(bool considerOverlap) const
1487 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1489 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1490 // m_contentIsOpaque, so don't take the fast path for composited layers
1491 // if they are a platform widget in order to get painting correctness
1492 // for transparent layers. See the comment in WidgetMac::paint.
1493 if (contentsInCompositedLayer() && !platformWidget())
1496 bool isOverlapped = m_isOverlapped && considerOverlap;
1498 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1501 if (FrameView* parentView = parentFrameView())
1502 return parentView->useSlowRepaints(considerOverlap);
1507 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1509 return useSlowRepaints(false);
1512 void FrameView::updateCanBlitOnScrollRecursively()
1514 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1515 if (FrameView* view = frame->view())
1516 view->setCanBlitOnScroll(!view->useSlowRepaints());
1520 bool FrameView::contentsInCompositedLayer() const
1522 RenderView* renderView = this->renderView();
1523 if (renderView && renderView->isComposited()) {
1524 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1525 if (layer && layer->drawsContent())
1532 void FrameView::setCannotBlitToWindow()
1534 m_cannotBlitToWindow = true;
1535 updateCanBlitOnScrollRecursively();
1538 void FrameView::addSlowRepaintObject(RenderElement* o)
1540 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1542 if (!m_slowRepaintObjects)
1543 m_slowRepaintObjects = std::make_unique<HashSet<RenderElement*>>();
1545 m_slowRepaintObjects->add(o);
1547 if (!hadSlowRepaintObjects) {
1548 updateCanBlitOnScrollRecursively();
1550 if (Page* page = frame().page()) {
1551 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1552 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1557 void FrameView::removeSlowRepaintObject(RenderElement* o)
1559 if (!m_slowRepaintObjects)
1562 m_slowRepaintObjects->remove(o);
1563 if (m_slowRepaintObjects->isEmpty()) {
1564 m_slowRepaintObjects = nullptr;
1565 updateCanBlitOnScrollRecursively();
1567 if (Page* page = frame().page()) {
1568 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1569 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1574 void FrameView::addViewportConstrainedObject(RenderElement* object)
1576 if (!m_viewportConstrainedObjects)
1577 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1579 if (!m_viewportConstrainedObjects->contains(object)) {
1580 m_viewportConstrainedObjects->add(object);
1581 if (platformWidget())
1582 updateCanBlitOnScrollRecursively();
1584 if (Page* page = frame().page()) {
1585 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1586 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1591 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1593 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1594 if (Page* page = frame().page()) {
1595 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1596 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1599 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1600 // why isn't the same check being made here?
1601 updateCanBlitOnScrollRecursively();
1605 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1608 if (useCustomFixedPositionLayoutRect())
1609 return customFixedPositionLayoutRect();
1611 LayoutRect viewportRect = visibleContentRect();
1613 viewportRect.setLocation(toLayoutPoint(scrollOffsetForFixedPosition()));
1614 return viewportRect;
1617 LayoutSize FrameView::scrollOffsetForFixedPosition(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, const LayoutPoint& scrollPosition, const LayoutPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements behaviorForFixed, int headerHeight, int footerHeight)
1619 LayoutPoint position;
1620 if (behaviorForFixed == StickToDocumentBounds)
1621 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1623 position = scrollPosition;
1624 position.setY(position.y() - headerHeight);
1627 LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
1629 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1630 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1632 return LayoutSize(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1635 LayoutSize FrameView::scrollOffsetForFixedPosition() const
1637 IntRect visibleContentRect = this->visibleContentRect();
1638 IntSize totalContentsSize = this->totalContentsSize();
1639 IntPoint scrollPosition = this->scrollPosition();
1640 IntPoint scrollOrigin = this->scrollOrigin();
1641 float frameScaleFactor = frame().frameScaleFactor();
1642 ScrollBehaviorForFixedElements behaviorForFixed = scrollBehaviorForFixedElements();
1643 return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), behaviorForFixed, headerHeight(), footerHeight());
1646 float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset)
1648 if (!topContentInset)
1651 // The insetClipLayer should not move for negative scroll values.
1652 float scrollY = std::max<float>(0, scrollPosition.y());
1654 if (scrollY >= topContentInset)
1657 return topContentInset - scrollY;
1660 float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset)
1662 if (!topContentInset)
1665 float scrollY = std::max<float>(0, scrollPosition.y());
1667 if (scrollY >= topContentInset)
1668 return topContentInset;
1673 float FrameView::yPositionForRootContentLayer(const FloatPoint& scrollPosition, float topContentInset, float headerHeight)
1675 return yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight;
1678 float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight)
1680 return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight;
1684 LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
1686 if (fixedElementsLayoutRelativeToFrame)
1687 return visibleContentRect;
1689 if (totalContentsSize.isEmpty())
1690 return visibleContentRect;
1692 // We impose an lower limit on the size (so an upper limit on the scale) of
1693 // the rect used to position fixed objects so that they don't crowd into the
1694 // center of the screen at larger scales.
1695 const LayoutUnit maxContentWidthForZoomThreshold = LayoutUnit::fromPixel(1024);
1696 float zoomedOutScale = frameScaleFactor * visibleContentRect.width() / std::min(maxContentWidthForZoomThreshold, totalContentsSize.width());
1697 float constraintThresholdScale = 1.5 * zoomedOutScale;
1698 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
1700 LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
1702 if (frameScaleFactor > constraintThresholdScale) {
1703 FloatRect contentRect(FloatPoint(), totalContentsSize);
1704 FloatRect viewportRect = visibleContentRect;
1706 // Scale the rect up from a point that is relative to its position in the viewport.
1707 FloatSize sizeDelta = contentRect.size() - viewportRect.size();
1709 FloatPoint scaleOrigin;
1710 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
1711 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
1713 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
1714 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
1715 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
1717 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
1720 if (scrollBehavior == StickToDocumentBounds) {
1721 LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
1722 viewportConstrainedObjectsRect.intersect(documentBounds);
1725 return viewportConstrainedObjectsRect;
1728 LayoutRect FrameView::viewportConstrainedObjectsRect() const
1730 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
1734 IntPoint FrameView::minimumScrollPosition() const
1736 IntPoint minimumPosition(ScrollView::minimumScrollPosition());
1738 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
1739 minimumPosition.setY(maximumScrollPosition().y());
1741 return minimumPosition;
1744 IntPoint FrameView::maximumScrollPosition() const
1746 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
1748 maximumOffset.clampNegativeToZero();
1750 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
1751 maximumOffset.setY(minimumScrollPosition().y());
1753 return maximumOffset;
1756 void FrameView::delayedScrollEventTimerFired()
1761 void FrameView::viewportContentsChanged()
1763 // When the viewport contents changes (scroll, resize, style recalc, layout, ...),
1764 // check if we should resume animated images or unthrottle DOM timers.
1765 resumeVisibleImageAnimationsIncludingSubframes();
1766 updateThrottledDOMTimersState();
1769 bool FrameView::fixedElementsLayoutRelativeToFrame() const
1771 return frame().settings().fixedElementsLayoutRelativeToFrame();
1774 IntPoint FrameView::lastKnownMousePosition() const
1776 return frame().eventHandler().lastKnownMousePosition();
1779 bool FrameView::isHandlingWheelEvent() const
1781 return frame().eventHandler().isHandlingWheelEvent();
1784 bool FrameView::shouldSetCursor() const
1786 Page* page = frame().page();
1787 return page && page->isVisible() && page->focusController().isActive();
1790 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1792 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1793 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1797 const bool isCompositedContentLayer = contentsInCompositedLayer();
1799 // Get the rects of the fixed objects visible in the rectToScroll
1800 Region regionToUpdate;
1801 for (auto& renderer : *m_viewportConstrainedObjects) {
1802 if (!renderer->style().hasViewportConstrainedPosition())
1804 if (renderer->isComposited())
1807 // Fixed items should always have layers.
1808 ASSERT(renderer->hasLayer());
1809 RenderLayer* layer = downcast<RenderBoxModelObject>(*renderer).layer();
1811 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1812 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1813 // Don't invalidate for invisible fixed layers.
1817 if (layer->hasAncestorWithFilterOutsets()) {
1818 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1819 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1823 // FIXME: use pixel snapping instead of enclosing when ScrollView has finished transitioning from IntRect to Float/LayoutRect.
1824 IntRect updateRect = enclosingIntRect(layer->repaintRectIncludingNonCompositingDescendants());
1825 updateRect = contentsToRootView(updateRect);
1826 if (!isCompositedContentLayer && clipsRepaints())
1827 updateRect.intersect(rectToScroll);
1828 if (!updateRect.isEmpty())
1829 regionToUpdate.unite(updateRect);
1833 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1835 // 2) update the area of fixed objects that has been invalidated
1836 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1837 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1838 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1839 IntRect updateRect = subRectsToUpdate[i];
1840 IntRect scrolledRect = updateRect;
1841 scrolledRect.move(scrollDelta);
1842 updateRect.unite(scrolledRect);
1843 if (isCompositedContentLayer) {
1844 updateRect = rootViewToContents(updateRect);
1845 ASSERT(renderView());
1846 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1849 if (clipsRepaints())
1850 updateRect.intersect(rectToScroll);
1851 hostWindow()->invalidateContentsAndRootView(updateRect);
1857 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1859 if (contentsInCompositedLayer()) {
1860 // FIXME: respect paintsEntireContents()?
1861 IntRect updateRect = visibleContentRect(LegacyIOSDocumentVisibleRect);
1863 // Make sure to "apply" the scale factor here since we're converting from frame view
1864 // coordinates to layer backing coordinates.
1865 updateRect.scale(1 / frame().frameScaleFactor());
1867 ASSERT(renderView());
1868 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect, GraphicsLayer::DoNotClipToLayer);
1871 repaintSlowRepaintObjects();
1873 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
1874 if (isEnclosedInCompositingLayer()) {
1875 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1876 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1877 visibleWidth(), visibleHeight());
1878 frameRenderer->repaintRectangle(rect);
1883 ScrollView::scrollContentsSlowPath(updateRect);
1886 void FrameView::repaintSlowRepaintObjects()
1888 if (!m_slowRepaintObjects)
1891 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
1892 // repaint them after scrolling.
1893 for (auto& renderer : *m_slowRepaintObjects)
1894 renderer->repaintSlowRepaintObject();
1897 // Note that this gets called at painting time.
1898 void FrameView::setIsOverlapped(bool isOverlapped)
1900 if (isOverlapped == m_isOverlapped)
1903 m_isOverlapped = isOverlapped;
1904 updateCanBlitOnScrollRecursively();
1906 if (hasCompositedContentIncludingDescendants()) {
1907 // Overlap can affect compositing tests, so if it changes, we need to trigger
1908 // a layer update in the parent document.
1909 if (Frame* parentFrame = frame().tree().parent()) {
1910 if (RenderView* parentView = parentFrame->contentRenderer()) {
1911 RenderLayerCompositor& compositor = parentView->compositor();
1912 compositor.setCompositingLayersNeedRebuild();
1913 compositor.scheduleCompositingLayerUpdate();
1917 if (RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) {
1918 // We also need to trigger reevaluation for this and all descendant frames,
1919 // since a frame uses compositing if any ancestor is compositing.
1920 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1921 if (RenderView* view = frame->contentRenderer()) {
1922 RenderLayerCompositor& compositor = view->compositor();
1923 compositor.setCompositingLayersNeedRebuild();
1924 compositor.scheduleCompositingLayerUpdate();
1931 bool FrameView::isOverlappedIncludingAncestors() const
1936 if (FrameView* parentView = parentFrameView()) {
1937 if (parentView->isOverlapped())
1944 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1946 if (contentIsOpaque == m_contentIsOpaque)
1949 m_contentIsOpaque = contentIsOpaque;
1950 updateCanBlitOnScrollRecursively();
1953 void FrameView::restoreScrollbar()
1955 setScrollbarsSuppressed(false);
1958 bool FrameView::scrollToFragment(const URL& url)
1960 // If our URL has no ref, then we have no place we need to jump to.
1961 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1962 // and possibly repaint because :target pseudo class may have been
1963 // set (see bug 11321).
1964 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
1967 String fragmentIdentifier = url.fragmentIdentifier();
1968 if (scrollToAnchor(fragmentIdentifier))
1971 // Try again after decoding the ref, based on the document's encoding.
1972 if (TextResourceDecoder* decoder = frame().document()->decoder())
1973 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
1978 bool FrameView::scrollToAnchor(const String& name)
1980 ASSERT(frame().document());
1981 auto& document = *frame().document();
1983 if (!document.haveStylesheetsLoaded()) {
1984 document.setGotoAnchorNeededAfterStylesheetsLoad(true);
1988 document.setGotoAnchorNeededAfterStylesheetsLoad(false);
1990 Element* anchorElement = document.findAnchor(name);
1992 // Setting to null will clear the current target.
1993 document.setCSSTarget(anchorElement);
1995 if (is<SVGDocument>(document)) {
1996 if (auto* rootElement = downcast<SVGDocument>(document).rootElement()) {
1997 rootElement->scrollToAnchor(name, anchorElement);
2003 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2004 if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top")))
2007 ContainerNode* scrollPositionAnchor = anchorElement;
2008 if (!scrollPositionAnchor)
2009 scrollPositionAnchor = frame().document();
2010 maintainScrollPositionAtAnchor(scrollPositionAnchor);
2012 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
2013 if (anchorElement && anchorElement->isFocusable())
2014 document.setFocusedElement(anchorElement);
2019 void FrameView::maintainScrollPositionAtAnchor(ContainerNode* anchorNode)
2021 m_maintainScrollPositionAnchor = anchorNode;
2022 if (!m_maintainScrollPositionAnchor)
2025 // We need to update the layout before scrolling, otherwise we could
2026 // really mess things up if an anchor scroll comes at a bad moment.
2027 frame().document()->updateStyleIfNeeded();
2028 // Only do a layout if changes have occurred that make it necessary.
2029 RenderView* renderView = this->renderView();
2030 if (renderView && renderView->needsLayout())
2036 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
2038 frame().document()->updateLayoutIgnorePendingStylesheets();
2041 if (RenderElement* renderer = element->renderer())
2042 bounds = renderer->anchorRect();
2043 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
2044 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
2045 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
2048 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
2050 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
2051 m_maintainScrollPositionAnchor = nullptr;
2052 ScrollView::setScrollPosition(scrollPoint);
2055 void FrameView::delegatesScrollingDidChange()
2057 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
2058 if (hasCompositedContent())
2059 clearBackingStores();
2062 #if USE(TILED_BACKING_STORE)
2063 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
2065 bool visibleContentSizeDidChange = false;
2066 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
2067 // When the viewport size changes or the content is scaled, we need to
2068 // reposition the fixed and sticky positioned elements.
2069 setViewportConstrainedObjectsNeedLayout();
2070 visibleContentSizeDidChange = true;
2073 IntSize offset = scrollOffset();
2074 IntPoint oldPosition = scrollPosition();
2075 ScrollView::setFixedVisibleContentRect(visibleContentRect);
2076 if (offset != scrollOffset()) {
2077 updateLayerPositionsAfterScrolling();
2078 if (frame().page()->settings().acceleratedCompositingForFixedPositionEnabled())
2079 updateCompositingLayersAfterScrolling();
2080 IntPoint newPosition = scrollPosition();
2081 scrollAnimator().setCurrentPosition(scrollPosition());
2082 scrollPositionChanged(oldPosition, newPosition);
2084 if (visibleContentSizeDidChange) {
2085 // Update the scroll-bars to calculate new page-step size.
2086 updateScrollbars(scrollOffset());
2088 didChangeScrollOffset();
2092 void FrameView::setViewportConstrainedObjectsNeedLayout()
2094 if (!hasViewportConstrainedObjects())
2097 for (auto& renderer : *m_viewportConstrainedObjects)
2098 renderer->setNeedsLayout();
2101 void FrameView::didChangeScrollOffset()
2103 frame().mainFrame().pageOverlayController().didScrollFrame(frame());
2104 frame().loader().client().didChangeScrollOffset();
2107 void FrameView::scrollPositionChangedViaPlatformWidgetImpl(const IntPoint& oldPosition, const IntPoint& newPosition)
2109 updateLayerPositionsAfterScrolling();
2110 updateCompositingLayersAfterScrolling();
2111 repaintSlowRepaintObjects();
2112 scrollPositionChanged(oldPosition, newPosition);
2115 void FrameView::scrollPositionChanged(const IntPoint& oldPosition, const IntPoint& newPosition)
2117 std::chrono::milliseconds throttlingDelay = frame().page()->chrome().client().eventThrottlingDelay();
2119 if (throttlingDelay == std::chrono::milliseconds::zero()) {
2120 m_delayedScrollEventTimer.stop();
2122 } else if (!m_delayedScrollEventTimer.isActive())
2123 m_delayedScrollEventTimer.startOneShot(throttlingDelay);
2125 if (Document* document = frame().document())
2126 document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize());
2128 if (RenderView* renderView = this->renderView()) {
2129 if (renderView->usesCompositing())
2130 renderView->compositor().frameViewDidScroll();
2133 viewportContentsChanged();
2136 void FrameView::resumeVisibleImageAnimationsIncludingSubframes()
2138 // A change in scroll position may affect image visibility in subframes.
2139 for (auto* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2140 if (auto* renderView = frame->contentRenderer())
2141 renderView->resumePausedImageAnimationsIfNeeded();
2145 void FrameView::updateLayerPositionsAfterScrolling()
2147 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2148 if (m_layoutPhase == InViewSizeAdjust)
2151 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2152 if (RenderView* renderView = this->renderView()) {
2153 updateWidgetPositions();
2154 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2159 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2161 #if ENABLE(ASYNC_SCROLLING)
2162 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2164 Page* page = frame().page();
2168 if (&page->mainFrame() != &frame())
2171 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2172 if (!scrollingCoordinator)
2175 if (!scrollingCoordinator->supportsFixedPositionLayers())
2178 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2181 if (inProgrammaticScroll())
2189 void FrameView::updateCompositingLayersAfterScrolling()
2191 ASSERT(m_layoutPhase >= InPostLayout || m_layoutPhase == OutsideLayout);
2193 if (!shouldUpdateCompositingLayersAfterScrolling())
2196 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2197 if (RenderView* renderView = this->renderView())
2198 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2202 bool FrameView::isRubberBandInProgress() const
2204 if (scrollbarsSuppressed())
2207 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2208 // ScrollingCoordinator::isRubberBandInProgress().
2209 if (Page* page = frame().page()) {
2210 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2211 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2212 return scrollingCoordinator->isRubberBandInProgress();
2216 // If the main thread updates the scroll position for this FrameView, we should return
2217 // ScrollAnimator::isRubberBandInProgress().
2218 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2219 return scrollAnimator->isRubberBandInProgress();
2224 bool FrameView::requestScrollPositionUpdate(const IntPoint& position)
2226 #if ENABLE(ASYNC_SCROLLING)
2227 if (TiledBacking* tiledBacking = this->tiledBacking())
2228 tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size()));
2231 #if ENABLE(ASYNC_SCROLLING) || USE(TILED_BACKING_STORE)
2232 if (Page* page = frame().page()) {
2233 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2234 return scrollingCoordinator->requestScrollPositionUpdate(this, position);
2237 UNUSED_PARAM(position);
2243 HostWindow* FrameView::hostWindow() const
2245 if (Page* page = frame().page())
2246 return &page->chrome();
2250 void FrameView::addTrackedRepaintRect(const FloatRect& r)
2252 if (!m_isTrackingRepaints || r.isEmpty())
2255 FloatRect repaintRect = r;
2256 repaintRect.move(-scrollOffset());
2257 m_trackedRepaintRects.append(repaintRect);
2260 void FrameView::repaintContentRectangle(const IntRect& r)
2262 ASSERT(!frame().ownerElement());
2264 if (!shouldUpdate())
2267 ScrollView::repaintContentRectangle(r);
2270 static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderElement& renderer, unsigned threshold)
2273 for (const RenderObject* descendant = &renderer; descendant; descendant = descendant->nextInPreOrder()) {
2274 if (is<RenderText>(*descendant)) {
2275 count += downcast<RenderText>(*descendant).text()->length();
2276 if (count >= threshold)
2283 bool FrameView::renderedCharactersExceed(unsigned threshold)
2285 if (!m_frame->contentRenderer())
2287 return countRenderedCharactersInRenderObjectWithThreshold(*m_frame->contentRenderer(), threshold) >= threshold;
2290 void FrameView::availableContentSizeChanged(AvailableSizeChangeReason reason)
2292 if (Document* document = frame().document())
2293 document->updateViewportUnitsOnResize();
2296 ScrollView::availableContentSizeChanged(reason);
2299 bool FrameView::shouldLayoutAfterContentsResized() const
2301 return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2304 void FrameView::updateContentsSize()
2306 // We check to make sure the view is attached to a frame() as this method can
2307 // be triggered before the view is attached by Frame::createView(...) setting
2308 // various values such as setScrollBarModes(...) for example. An ASSERT is
2309 // triggered when a view is layout before being attached to a frame().
2310 if (!frame().view())
2314 if (RenderView* root = m_frame->contentRenderer()) {
2315 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2316 setViewportConstrainedObjectsNeedLayout();
2317 // We must eagerly enter compositing mode because fixed position elements
2318 // will not have been made compositing via a preceding style change before
2319 // m_useCustomFixedPositionLayoutRect was true.
2320 root->compositor().enableCompositingMode();
2325 if (shouldLayoutAfterContentsResized() && needsLayout())
2328 if (RenderView* renderView = this->renderView()) {
2329 if (renderView->usesCompositing())
2330 renderView->compositor().frameViewDidChangeSize();
2334 void FrameView::addedOrRemovedScrollbar()
2336 if (RenderView* renderView = this->renderView()) {
2337 if (renderView->usesCompositing())
2338 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2342 static LayerFlushThrottleState::Flags determineLayerFlushThrottleState(Page& page)
2344 // We only throttle when constantly receiving new data during the inital page load.
2345 if (!page.progress().isMainLoadProgressing())
2347 // Scrolling during page loading disables throttling.
2348 if (page.mainFrame().view()->wasScrolledByUser())
2350 // Disable for image documents so large GIF animations don't get throttled during loading.
2351 auto* document = page.mainFrame().document();
2352 if (!document || is<ImageDocument>(*document))
2354 return LayerFlushThrottleState::Enabled;
2357 void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2359 if (!frame().page())
2361 auto& page = *frame().page();
2363 LayerFlushThrottleState::Flags flags = LayerFlushThrottleState::UserIsInteracting | determineLayerFlushThrottleState(page);
2364 if (page.chrome().client().adjustLayerFlushThrottling(flags))
2367 if (RenderView* view = renderView())
2368 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2371 void FrameView::loadProgressingStatusChanged()
2373 updateLayerFlushThrottling();
2374 adjustTiledBackingCoverage();
2377 void FrameView::updateLayerFlushThrottling()
2379 ASSERT(frame().isMainFrame());
2380 auto& page = *frame().page();
2382 LayerFlushThrottleState::Flags flags = determineLayerFlushThrottleState(page);
2384 // See if the client is handling throttling.
2385 if (page.chrome().client().adjustLayerFlushThrottling(flags))
2388 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2389 if (RenderView* renderView = frame->contentRenderer())
2390 renderView->compositor().setLayerFlushThrottlingEnabled(flags & LayerFlushThrottleState::Enabled);
2394 void FrameView::adjustTiledBackingCoverage()
2396 if (!m_speculativeTilingEnabled)
2397 enableSpeculativeTilingIfNeeded();
2399 RenderView* renderView = this->renderView();
2400 if (renderView && renderView->layer()->backing())
2401 renderView->layer()->backing()->adjustTiledBackingCoverage();
2403 if (LegacyTileCache* tileCache = legacyTileCache())
2404 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2408 static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2410 return view.isVisuallyNonEmpty() && !view.frame().page()->progress().isMainLoadProgressing();
2413 void FrameView::enableSpeculativeTilingIfNeeded()
2415 ASSERT(!m_speculativeTilingEnabled);
2416 if (m_wasScrolledByUser) {
2417 m_speculativeTilingEnabled = true;
2420 if (!shouldEnableSpeculativeTilingDuringLoading(*this))
2422 if (m_speculativeTilingEnableTimer.isActive())
2424 // Delay enabling a bit as load completion may trigger further loading from scripts.
2425 static const double speculativeTilingEnableDelay = 0.5;
2426 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
2429 void FrameView::speculativeTilingEnableTimerFired()
2431 if (m_speculativeTilingEnabled)
2433 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
2434 adjustTiledBackingCoverage();
2437 void FrameView::layoutTimerFired()
2439 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2440 if (!frame().document()->ownerElement())
2441 printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count());
2446 void FrameView::scheduleRelayout()
2448 // FIXME: We should assert the page is not in the page cache, but that is causing
2449 // too many false assertions. See <rdar://problem/7218118>.
2450 ASSERT(frame().view() == this);
2453 m_layoutRoot->markContainingBlocksForLayout(false);
2454 m_layoutRoot = nullptr;
2456 if (!m_layoutSchedulingEnabled)
2460 if (!frame().document()->shouldScheduleLayout())
2462 InspectorInstrumentation::didInvalidateLayout(frame());
2463 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2464 // Also invalidate parent frame starting from the owner element of this frame.
2465 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2466 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2468 std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay();
2469 if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count())
2470 unscheduleRelayout();
2471 if (m_layoutTimer.isActive())
2474 m_delayedLayout = delay.count();
2476 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2477 if (!frame().document()->ownerElement())
2478 printf("Scheduling layout for %d\n", delay);
2481 m_layoutTimer.startOneShot(delay);
2484 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2486 for (RenderObject* r = descendant; r; r = r->container()) {
2493 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2495 ASSERT(renderView());
2496 RenderView& renderView = *this->renderView();
2498 // Try to catch unnecessary work during render tree teardown.
2499 ASSERT(!renderView.documentBeingDestroyed());
2500 ASSERT(frame().view() == this);
2502 if (renderView.needsLayout()) {
2503 newRelayoutRoot.markContainingBlocksForLayout(false);
2507 if (!layoutPending() && m_layoutSchedulingEnabled) {
2508 std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay();
2509 ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout());
2510 m_layoutRoot = &newRelayoutRoot;
2511 InspectorInstrumentation::didInvalidateLayout(frame());
2512 m_delayedLayout = delay.count();
2513 m_layoutTimer.startOneShot(delay);
2517 if (m_layoutRoot == &newRelayoutRoot)
2520 if (!m_layoutRoot) {
2521 // Just relayout the subtree.
2522 newRelayoutRoot.markContainingBlocksForLayout(false);
2523 InspectorInstrumentation::didInvalidateLayout(frame());
2527 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2528 // Keep the current root.
2529 newRelayoutRoot.markContainingBlocksForLayout(false, m_layoutRoot);
2530 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2534 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2535 // Re-root at newRelayoutRoot.
2536 m_layoutRoot->markContainingBlocksForLayout(false, &newRelayoutRoot);
2537 m_layoutRoot = &newRelayoutRoot;
2538 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2539 InspectorInstrumentation::didInvalidateLayout(frame());
2543 // Just do a full relayout.
2544 m_layoutRoot->markContainingBlocksForLayout(false);
2545 m_layoutRoot = nullptr;
2546 newRelayoutRoot.markContainingBlocksForLayout(false);
2547 InspectorInstrumentation::didInvalidateLayout(frame());
2550 bool FrameView::layoutPending() const
2552 return m_layoutTimer.isActive();
2555 bool FrameView::needsStyleRecalcOrLayout(bool includeSubframes) const
2557 if (frame().document() && frame().document()->childNeedsStyleRecalc())
2563 if (!includeSubframes)
2566 // Find child frames via the Widget tree, as updateLayoutAndStyleIfNeededRecursive() does.
2567 Vector<Ref<FrameView>, 16> childViews;
2568 childViews.reserveInitialCapacity(children().size());
2569 for (auto& widget : children()) {
2570 if (is<FrameView>(*widget))
2571 childViews.uncheckedAppend(downcast<FrameView>(*widget));
2574 for (unsigned i = 0; i < childViews.size(); ++i) {
2575 if (childViews[i]->needsStyleRecalcOrLayout())
2582 bool FrameView::needsLayout() const
2584 // This can return true in cases where the document does not have a body yet.
2585 // Document::shouldScheduleLayout takes care of preventing us from scheduling
2586 // layout in that case.
2587 RenderView* renderView = this->renderView();
2588 return layoutPending()
2589 || (renderView && renderView->needsLayout())
2591 || (m_deferSetNeedsLayoutCount && m_setNeedsLayoutWasDeferred);
2594 void FrameView::setNeedsLayout()
2596 if (m_deferSetNeedsLayoutCount) {
2597 m_setNeedsLayoutWasDeferred = true;
2601 if (RenderView* renderView = this->renderView())
2602 renderView->setNeedsLayout();
2605 void FrameView::unscheduleRelayout()
2607 if (!m_layoutTimer.isActive())
2610 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2611 if (!frame().document()->ownerElement())
2612 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
2615 m_layoutTimer.stop();
2616 m_delayedLayout = false;
2619 #if ENABLE(REQUEST_ANIMATION_FRAME)
2620 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
2622 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
2623 frame->view()->serviceScrollAnimations();
2624 frame->animation().serviceAnimations();
2627 Vector<RefPtr<Document>> documents;
2628 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext())
2629 documents.append(frame->document());
2631 for (size_t i = 0; i < documents.size(); ++i)
2632 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
2636 bool FrameView::isTransparent() const
2638 return m_isTransparent;
2641 void FrameView::setTransparent(bool isTransparent)
2643 if (m_isTransparent == isTransparent)
2646 m_isTransparent = isTransparent;
2648 RenderView* renderView = this->renderView();
2652 // setTransparent can be called in the window between FrameView initialization
2653 // and switching in the new Document; this means that the RenderView that we
2654 // retrieve is actually attached to the previous Document, which is going away,
2655 // and must not update compositing layers.
2656 if (&renderView->frameView() != this)
2659 RenderLayerCompositor& compositor = renderView->compositor();
2660 compositor.setCompositingLayersNeedRebuild();
2661 compositor.scheduleCompositingLayerUpdate();
2664 bool FrameView::hasOpaqueBackground() const
2666 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
2669 Color FrameView::baseBackgroundColor() const
2671 return m_baseBackgroundColor;
2674 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
2676 if (!backgroundColor.isValid())
2677 m_baseBackgroundColor = Color::white;
2679 m_baseBackgroundColor = backgroundColor;
2681 recalculateScrollbarOverlayStyle();
2684 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
2686 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2687 if (FrameView* view = frame->view()) {
2688 view->setTransparent(transparent);
2689 view->setBaseBackgroundColor(backgroundColor);
2694 bool FrameView::hasExtendedBackgroundRectForPainting() const
2696 if (!frame().settings().backgroundShouldExtendBeyondPage())
2699 TiledBacking* tiledBacking = this->tiledBacking();
2703 return tiledBacking->hasMargins();
2706 void FrameView::updateExtendBackgroundIfNecessary()
2708 ExtendedBackgroundMode mode = calculateExtendedBackgroundMode();
2709 if (mode == ExtendedBackgroundModeNone)
2712 updateTilesForExtendedBackgroundMode(mode);
2715 FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
2717 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
2718 // that the background rect needs to be extended for painting. Simple backgrounds can be extended
2719 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
2720 // such as images, require extending the background rect to continue painting into the extended
2721 // region. This function finds out if it is necessary to extend the background rect for painting.
2724 // <rdar://problem/16201373>
2725 return ExtendedBackgroundModeNone;
2728 if (!frame().settings().backgroundShouldExtendBeyondPage())
2729 return ExtendedBackgroundModeNone;
2731 if (!frame().isMainFrame())
2732 return ExtendedBackgroundModeNone;
2734 Document* document = frame().document();
2736 return ExtendedBackgroundModeNone;
2738 auto documentElement = document->documentElement();
2739 auto documentElementRenderer = documentElement ? documentElement->renderer() : nullptr;
2740 if (!documentElementRenderer)
2741 return ExtendedBackgroundModeNone;
2743 auto& renderer = documentElementRenderer->rendererForRootBackground();
2744 if (!renderer.style().hasBackgroundImage())
2745 return ExtendedBackgroundModeNone;
2747 ExtendedBackgroundMode mode = ExtendedBackgroundModeNone;
2749 if (renderer.style().backgroundRepeatX() == RepeatFill)
2750 mode |= ExtendedBackgroundModeHorizontal;
2751 if (renderer.style().backgroundRepeatY() == RepeatFill)
2752 mode |= ExtendedBackgroundModeVertical;
2757 void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
2759 if (!frame().settings().backgroundShouldExtendBeyondPage())
2762 RenderView* renderView = this->renderView();
2766 RenderLayerBacking* backing = renderView->layer()->backing();
2770 TiledBacking* tiledBacking = backing->graphicsLayer()->tiledBacking();
2774 ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone;
2775 if (tiledBacking->hasVerticalMargins())
2776 existingMode |= ExtendedBackgroundModeVertical;
2777 if (tiledBacking->hasHorizontalMargins())
2778 existingMode |= ExtendedBackgroundModeHorizontal;
2780 if (existingMode == mode)
2783 renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor());
2784 backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical);
2787 IntRect FrameView::extendedBackgroundRectForPainting() const
2789 TiledBacking* tiledBacking = this->tiledBacking();
2793 RenderView* renderView = this->renderView();
2797 LayoutRect extendedRect = renderView->unextendedBackgroundRect(renderView);
2798 if (!tiledBacking->hasMargins())
2799 return snappedIntRect(extendedRect);
2801 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
2802 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
2803 return snappedIntRect(extendedRect);
2806 bool FrameView::shouldUpdateWhileOffscreen() const
2808 return m_shouldUpdateWhileOffscreen;
2811 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
2813 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
2816 bool FrameView::shouldUpdate() const
2818 if (isOffscreen() && !shouldUpdateWhileOffscreen())
2823 void FrameView::scrollToAnchor()
2825 RefPtr<ContainerNode> anchorNode = m_maintainScrollPositionAnchor;
2829 if (!anchorNode->renderer())
2833 if (anchorNode != frame().document() && anchorNode->renderer())
2834 rect = anchorNode->renderer()->anchorRect();
2836 // Scroll nested layers and frames to reveal the anchor.
2837 // Align to the top and to the closest side (this matches other browsers).
2838 if (anchorNode->renderer()->style().isHorizontalWritingMode())
2839 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
2840 else if (anchorNode->renderer()->style().isFlippedBlocksWritingMode())
2841 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignRightAlways, ScrollAlignment::alignToEdgeIfNeeded);
2843 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignLeftAlways, ScrollAlignment::alignToEdgeIfNeeded);
2845 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
2846 cache->handleScrolledToAnchor(anchorNode.get());
2848 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
2849 m_maintainScrollPositionAnchor = anchorNode;
2852 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
2854 // No need to update if it's already crashed or known to be missing.
2855 if (embeddedObject.isPluginUnavailable())
2858 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
2860 if (embeddedObject.isSnapshottedPlugIn()) {
2861 if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
2862 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
2863 pluginElement.checkSnapshotStatus();
2868 auto weakRenderer = embeddedObject.createWeakPtr();
2870 // FIXME: This could turn into a real virtual dispatch if we defined
2871 // updateWidget(PluginCreationOption) on HTMLElement.
2872 if (is<HTMLPlugInImageElement>(element)) {
2873 HTMLPlugInImageElement& pluginElement = downcast<HTMLPlugInImageElement>(element);
2874 if (pluginElement.needsCheckForSizeChange()) {
2875 pluginElement.checkSnapshotStatus();
2878 if (pluginElement.needsWidgetUpdate())
2879 pluginElement.updateWidget(CreateAnyWidgetType);
2881 ASSERT_NOT_REACHED();
2883 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
2887 embeddedObject.updateWidgetPosition();
2890 bool FrameView::updateEmbeddedObjects()
2892 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
2895 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
2897 // Insert a marker for where we should stop.
2898 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
2899 m_embeddedObjectsToUpdate->add(nullptr);
2901 while (!m_embeddedObjectsToUpdate->isEmpty()) {
2902 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
2903 if (!embeddedObject)
2905 updateEmbeddedObject(*embeddedObject);
2908 return m_embeddedObjectsToUpdate->isEmpty();
2911 void FrameView::updateEmbeddedObjectsTimerFired()
2913 RefPtr<FrameView> protect(this);
2914 m_updateEmbeddedObjectsTimer.stop();
2915 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
2916 if (updateEmbeddedObjects())
2921 void FrameView::flushAnyPendingPostLayoutTasks()
2923 if (m_postLayoutTasksTimer.isActive())
2924 performPostLayoutTasks();
2925 if (m_updateEmbeddedObjectsTimer.isActive())
2926 updateEmbeddedObjectsTimerFired();
2929 void FrameView::performPostLayoutTasks()
2931 // FIXME: We should not run any JavaScript code in this function.
2933 m_postLayoutTasksTimer.stop();
2935 frame().selection().didLayout();
2937 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
2938 fireLayoutRelatedMilestonesIfNeeded();
2941 // Only send layout-related delegate callbacks synchronously for the main frame to
2942 // avoid re-entering layout for the main frame while delivering a layout-related delegate
2943 // callback for a subframe.
2944 if (frame().isMainFrame())
2945 frame().page()->chrome().client().didLayout();
2948 #if ENABLE(FONT_LOAD_EVENTS)
2949 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
2950 frame().document()->fonts()->didLayout();
2953 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
2954 // with didLayout(LayoutMilestones).
2955 frame().loader().client().dispatchDidLayout();
2957 updateWidgetPositions();
2959 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
2960 // is called through the post layout timer.
2961 Ref<FrameView> protect(*this);
2963 m_updateEmbeddedObjectsTimer.startOneShot(0);
2965 if (auto* page = frame().page()) {
2966 if (auto* scrollingCoordinator = page->scrollingCoordinator())
2967 scrollingCoordinator->frameViewLayoutUpdated(this);
2970 if (RenderView* renderView = this->renderView()) {
2971 if (renderView->usesCompositing())
2972 renderView->compositor().frameViewDidLayout();
2977 sendResizeEventIfNeeded();
2978 viewportContentsChanged();
2981 IntSize FrameView::sizeForResizeEvent() const
2984 if (m_useCustomSizeForResizeEvent)
2985 return m_customSizeForResizeEvent;
2987 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
2988 return fixedLayoutSize();
2989 return visibleContentRectIncludingScrollbars().size();
2992 void FrameView::sendResizeEventIfNeeded()
2994 if (isInLayout() || needsLayout())
2997 RenderView* renderView = this->renderView();
2998 if (!renderView || renderView->printing())
3001 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
3004 IntSize currentSize = sizeForResizeEvent();
3005 float currentZoomFactor = renderView->style().zoom();
3007 if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor)
3010 m_lastViewportSize = currentSize;
3011 m_lastZoomFactor = currentZoomFactor;
3017 // Don't send the resize event if the document is loading. Some pages automatically reload
3018 // when the window is resized; Safari on iOS often resizes the window while setting up its
3019 // viewport. This obviously can cause problems.
3020 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
3021 if (documentLoader->isLoadingInAPISense())
3026 bool isMainFrame = frame().isMainFrame();
3027 bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize;
3029 RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
3030 if (canSendResizeEventSynchronously)
3031 frame().document()->dispatchWindowEvent(resizeEvent.release());
3033 // FIXME: Queueing this event for an unpredictable time in the future seems
3034 // intrinsically racy. By the time this resize event fires, the frame might
3035 // be resized again, so we could end up with two resize events for the same size.
3036 frame().document()->enqueueWindowEvent(resizeEvent.release());
3039 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
3040 if (Page* page = frame().page()) {
3041 if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient())
3042 inspectorClient->didResizeMainFrame(&frame());
3047 void FrameView::willStartLiveResize()
3049 ScrollView::willStartLiveResize();
3050 adjustTiledBackingCoverage();
3053 void FrameView::willEndLiveResize()
3055 ScrollView::willEndLiveResize();
3056 adjustTiledBackingCoverage();
3059 void FrameView::postLayoutTimerFired()
3061 performPostLayoutTasks();
3064 void FrameView::registerThrottledDOMTimer(DOMTimer* timer)
3066 m_throttledTimers.add(timer);
3069 void FrameView::unregisterThrottledDOMTimer(DOMTimer* timer)
3071 m_throttledTimers.remove(timer);
3074 void FrameView::updateThrottledDOMTimersState()
3076 if (m_throttledTimers.isEmpty())
3079 IntRect visibleRect = windowToContents(windowClipRect());
3081 // Do not iterate over the HashSet because calling DOMTimer::updateThrottlingStateAfterViewportChange()
3082 // may cause timers to remove themselves from it while we are iterating.
3083 Vector<DOMTimer*> timers;
3084 copyToVector(m_throttledTimers, timers);
3085 for (auto* timer : timers)
3086 timer->updateThrottlingStateAfterViewportChange(visibleRect);
3089 void FrameView::autoSizeIfEnabled()
3091 if (!m_shouldAutoSize)
3097 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
3099 Document* document = frame().document();
3103 RenderView* documentView = document->renderView();
3104 Element* documentElement = document->documentElement();
3105 if (!documentView || !documentElement)
3108 // Start from the minimum size and allow it to grow.
3109 resize(m_minAutoSize.width(), m_minAutoSize.height());
3111 IntSize size = frameRect().size();
3113 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
3114 // which may result in a height change during the second iteration.
3115 for (int i = 0; i < 2; i++) {
3116 // Update various sizes including contentsSize, scrollHeight, etc.
3117 document->updateLayoutIgnorePendingStylesheets();
3118 int width = documentView->minPreferredLogicalWidth();
3119 int height = documentView->documentRect().height();
3120 IntSize newSize(width, height);
3122 // Check to see if a scrollbar is needed for a given dimension and
3123 // if so, increase the other dimension to account for the scrollbar.
3124 // Since the dimensions are only for the view rectangle, once a
3125 // dimension exceeds the maximum, there is no need to increase it further.
3126 if (newSize.width() > m_maxAutoSize.width()) {
3127 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
3128 if (!localHorizontalScrollbar)
3129 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
3130 if (!localHorizontalScrollbar->isOverlayScrollbar())
3131 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
3133 // Don't bother checking for a vertical scrollbar because the width is at
3134 // already greater the maximum.
3135 } else if (newSize.height() > m_maxAutoSize.height()) {
3136 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
3137 if (!localVerticalScrollbar)
3138 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
3139 if (!localVerticalScrollbar->isOverlayScrollbar())
3140 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
3142 // Don't bother checking for a horizontal scrollbar because the height is
3143 // already greater the maximum.
3146 // Ensure the size is at least the min bounds.
3147 newSize = newSize.expandedTo(m_minAutoSize);
3149 // Bound the dimensions by the max bounds and determine what scrollbars to show.
3150 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
3151 if (newSize.width() > m_maxAutoSize.width()) {
3152 newSize.setWidth(m_maxAutoSize.width());
3153 horizonalScrollbarMode = ScrollbarAlwaysOn;
3155 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
3156 if (newSize.height() > m_maxAutoSize.height()) {
3157 newSize.setHeight(m_maxAutoSize.height());
3158 verticalScrollbarMode = ScrollbarAlwaysOn;
3161 if (newSize == size)
3164 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
3165 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
3166 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
3167 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
3170 resize(newSize.width(), newSize.height());
3171 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
3172 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
3173 setVerticalScrollbarLock(false);
3174 setHorizontalScrollbarLock(false);
3175 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
3178 m_autoSizeContentSize = contentsSize();
3180 if (m_autoSizeFixedMinimumHeight) {
3181 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
3182 document->updateLayoutIgnorePendingStylesheets();
3185 m_didRunAutosize = true;
3188 void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
3190 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
3193 m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
3198 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
3200 if (!m_viewportRenderer)
3203 if (m_overflowStatusDirty) {
3204 m_horizontalOverflow = horizontalOverflow;
3205 m_verticalOverflow = verticalOverflow;
3206 m_overflowStatusDirty = false;
3210 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
3211 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
3213 if (horizontalOverflowChanged || verticalOverflowChanged) {
3214 m_horizontalOverflow = horizontalOverflow;
3215 m_verticalOverflow = verticalOverflow;
3217 RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
3218 verticalOverflowChanged, verticalOverflow);
3219 overflowEvent->setTarget(m_viewportRenderer->element());
3221 frame().document()->enqueueOverflowEvent(overflowEvent.release());
3225 const Pagination& FrameView::pagination() const
3227 if (m_pagination != Pagination())
3228 return m_pagination;
3230 if (frame().isMainFrame())
3231 return frame().page()->pagination();
3233 return m_pagination;
3236 void FrameView::setPagination(const Pagination& pagination)
3238 if (m_pagination == pagination)
3241 m_pagination = pagination;
3243 frame().document()->styleResolverChanged(DeferRecalcStyle);
3246 IntRect FrameView::windowClipRect() const
3248 ASSERT(frame().view() == this);
3250 if (paintsEntireContents())
3251 return contentsToWindow(IntRect(IntPoint(), totalContentsSize()));
3253 // Set our clip rect to be our contents.
3254 IntRect clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect));
3256 if (!frame().ownerElement())
3259 // Take our owner element and get its clip rect.
3260 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
3261 if (FrameView* parentView = ownerElement->document().view())
3262 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
3266 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
3268 // The renderer can sometimes be null when style="display:none" interacts
3269 // with external content and plugins.
3270 if (!ownerElement->renderer())
3271 return windowClipRect();
3273 // If we have no layer, just return our window clip rect.
3274 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
3275 if (!enclosingLayer)
3276 return windowClipRect();
3278 // Apply the clip from the layer.
3280 if (clipToLayerContents)
3281 clipRect = snappedIntRect(enclosingLayer->childrenClipRect());
3283 clipRect = snappedIntRect(enclosingLayer->selfClipRect());
3284 clipRect = contentsToWindow(clipRect);
3285 return intersection(clipRect, windowClipRect());
3288 bool FrameView::isActive() const
3290 Page* page = frame().page();
3291 return page && page->focusController().isActive();
3294 bool FrameView::updatesScrollLayerPositionOnMainThread() const
3296 if (Page* page = frame().page()) {
3297 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
3298 return scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously();
3304 bool FrameView::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
3306 Page* page = frame().page();
3307 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
3310 void FrameView::scrollTo(const IntSize& newOffset)
3312 LayoutSize offset = scrollOffset();
3313 IntPoint oldPosition = scrollPosition();
3314 ScrollView::scrollTo(newOffset);
3315 if (offset != scrollOffset())
3316 scrollPositionChanged(oldPosition, scrollPosition());
3317 didChangeScrollOffset();
3320 float FrameView::adjustScrollStepForFixedContent(float step, ScrollbarOrientation orientation, ScrollGranularity granularity)
3322 if (granularity != ScrollByPage || orientation == HorizontalScrollbar)
3325 TrackedRendererListHashSet* positionedObjects = nullptr;
3326 if (RenderView* root = m_frame->contentRenderer()) {
3327 if (!root->hasPositionedObjects())
3329 positionedObjects = root->positionedObjects();
3332 FloatRect unobscuredContentRect = this->unobscuredContentRect();
3333 float topObscuredArea = 0;
3334 float bottomObscuredArea = 0;
3335 for (const auto& positionedObject : *positionedObjects) {
3336 const RenderStyle& style = positionedObject->style();
3337 if (style.position() != FixedPosition || style.visibility() == HIDDEN || !style.opacity())
3340 FloatQuad contentQuad = positionedObject->absoluteContentQuad();
3341 if (!contentQuad.isRectilinear())
3344 FloatRect contentBoundingBox = contentQuad.boundingBox();
3345 FloatRect fixedRectInView = intersection(unobscuredContentRect, contentBoundingBox);
3347 if (fixedRectInView.width() < unobscuredContentRect.width())
3350 if (fixedRectInView.y() == unobscuredContentRect.y())
3351 topObscuredArea = std::max(topObscuredArea, fixedRectInView.height());
3352 else if (fixedRectInView.maxY() == unobscuredContentRect.maxY())
3353 bottomObscuredArea = std::max(bottomObscuredArea, fixedRectInView.height());
3356 return Scrollbar::pageStep(unobscuredContentRect.height(), unobscuredContentRect.height() - topObscuredArea - bottomObscuredArea);
3359 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
3361 // Add in our offset within the FrameView.
3362 IntRect dirtyRect = rect;
3363 dirtyRect.moveBy(scrollbar->location());
3364 invalidateRect(dirtyRect);
3367 IntRect FrameView::windowResizerRect() const
3369 if (Page* page = frame().page())
3370 return page->chrome().windowResizerRect();
3374 float FrameView::visibleContentScaleFactor() const
3376 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3379 return frame().page()->pageScaleFactor();
3382 void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3384 if (!frame().isMainFrame())
3387 frame().page()->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3390 ScrollableArea* FrameView::enclosingScrollableArea() const
3392 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3396 IntRect FrameView::scrollableAreaBoundingBox() const
3398 RenderWidget* ownerRenderer = frame().ownerRenderer();
3402 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3405 bool FrameView::isScrollable(Scrollability definitionOfScrollable)
3408 // 1) If there an actual overflow.
3409 // 2) display:none or visibility:hidden set to self or inherited.
3410 // 3) overflow{-x,-y}: hidden;
3411 // 4) scrolling: no;
3413 bool requiresActualOverflowToBeConsideredScrollable = !frame().isMainFrame() || definitionOfScrollable != Scrollability::ScrollableOrRubberbandable;
3414 #if !ENABLE(RUBBER_BANDING)
3415 requiresActualOverflowToBeConsideredScrollable = true;
3419 if (requiresActualOverflowToBeConsideredScrollable) {
3420 IntSize totalContentsSize = this->totalContentsSize();
3421 IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size();
3422 if (totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width())
3427 HTMLFrameOwnerElement* owner = frame().ownerElement();
3428 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3432 ScrollbarMode horizontalMode;
3433 ScrollbarMode verticalMode;
3434 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3435 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3441 bool FrameView::isScrollableOrRubberbandable()
3443 return isScrollable(Scrollability::ScrollableOrRubberbandable);
3446 bool FrameView::hasScrollableOrRubberbandableAncestor()
3448 if (frame().isMainFrame())
3449 return isScrollableOrRubberbandable();
3451 for (FrameView* parent = this->parentFrameView(); parent; parent = parent->parentFrameView()) {
3452 Scrollability frameScrollability = parent->frame().isMainFrame() ? Scrollability::ScrollableOrRubberbandable : Scrollability::Scrollable;
3453 if (parent->isScrollable(frameScrollability))
3460 void FrameView::updateScrollableAreaSet()
3462 // That ensures that only inner frames are cached.
3463 FrameView* parentFrameView = this->parentFrameView();
3464 if (!parentFrameView)
3467 if (!isScrollable()) {
3468 parentFrameView->removeScrollableArea(this);
3472 parentFrameView->addScrollableArea(this);
3475 bool FrameView::shouldSuspendScrollAnimations() const
3477 return frame().loader().state() != FrameStateComplete;
3480 void FrameView::scrollbarStyleChanged(ScrollbarStyle newStyle, bool forceUpdate)
3482 if (!frame().isMainFrame())
3485 frame().page()->chrome().client().recommendedScrollbarStyleDidChange(newStyle);
3487 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
3490 void FrameView::notifyPageThatContentAreaWillPaint() const
3492 Page* page = frame().page();
3496 contentAreaWillPaint();
3498 if (!m_scrollableAreas)
3501 for (auto& scrollableArea : *m_scrollableAreas)
3502 scrollableArea->contentAreaWillPaint();
3505 bool FrameView::scrollAnimatorEnabled() const
3507 #if ENABLE(SMOOTH_SCROLLING)
3508 if (Page* page = frame().page())
3509 return page->settings().scrollAnimatorEnabled();
3515 #if ENABLE(DASHBOARD_SUPPORT)
3516 void FrameView::updateAnnotatedRegions()
3518 Document* document = frame().document();
3519 if (!document->hasAnnotatedRegions())
3521 Vector<AnnotatedRegionValue> newRegions;
3522 document->renderBox()->collectAnnotatedRegions(newRegions);
3523 if (newRegions == document->annotatedRegions())
3525 document->setAnnotatedRegions(newRegions);
3526 Page* page = frame().page();
3529 page->chrome().client().annotatedRegionsChanged();
3533 void FrameView::updateScrollCorner()
3535 RenderElement* renderer = nullptr;
3536 RefPtr<RenderStyle> cornerStyle;
3537 IntRect cornerRect = scrollCornerRect();
3539 if (!cornerRect.isEmpty()) {
3540 // Try the <body> element first as a scroll corner source.
3541 Document* doc = frame().document();
3542 Element* body = doc ? doc->bodyOrFrameset() : nullptr;
3543 if (body && body->renderer()) {
3544 renderer = body->renderer();
3545 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3549 // If the <body> didn't have a custom style, then the root element might.
3550 Element* docElement = doc ? doc->documentElement() : nullptr;
3551 if (docElement && docElement->renderer()) {
3552 renderer = docElement->renderer();
3553 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3558 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
3559 if (RenderWidget* renderer = frame().ownerRenderer())
3560 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3565 m_scrollCorner = nullptr;
3567 if (!m_scrollCorner) {
3568 m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer->document(), cornerStyle.releaseNonNull());
3569 m_scrollCorner->initializeStyle();
3571 m_scrollCorner->setStyle(cornerStyle.releaseNonNull());
3572 invalidateScrollCorner(cornerRect);
3575 ScrollView::updateScrollCorner();
3578 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
3580 if (context->updatingControlTints()) {
3581 updateScrollCorner();
3585 if (m_scrollCorner) {
3586 if (frame().isMainFrame())
3587 context->fillRect(cornerRect, baseBackgroundColor(), ColorSpaceDeviceRGB);
3588 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
3592 ScrollView::paintScrollCorner(context, cornerRect);
3595 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
3597 if (bar->isCustomScrollbar() && frame().isMainFrame()) {
3598 IntRect toFill = bar->frameRect();
3599 toFill.intersect(rect);
3600 context->fillRect(toFill, baseBackgroundColor(), ColorSpaceDeviceRGB);
3603 ScrollView::paintScrollbar(context, bar, rect);
3606 Color FrameView::documentBackgroundColor() const
3608 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
3609 // the document and the body against the base background color of the frame view.
3610 // Background images are unfortunately impractical to include.
3612 // Return invalid Color objects whenever there is insufficient information.
3613 if (!frame().document())
3616 auto* htmlElement = frame().document()->documentElement();
3617 auto* bodyElement = frame().document()->bodyOrFrameset();
3619 // Start with invalid colors.
3620 Color htmlBackgroundColor;
3621 Color bodyBackgroundColor;
3622 if (htmlElement && htmlElement->renderer())
3623 htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3624 if (bodyElement && bodyElement->renderer())
3625 bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3627 if (!bodyBackgroundColor.isValid()) {
3628 if (!htmlBackgroundColor.isValid())
3630 return baseBackgroundColor().blend(htmlBackgroundColor);
3633 if (!htmlBackgroundColor.isValid())
3634 return baseBackgroundColor().blend(bodyBackgroundColor);
3636 // We take the aggregate of the base background color
3637 // the <html> background color, and the <body>
3638 // background color to find the document color. The
3639 // addition of the base background color is not
3640 // technically part of the document background, but it
3641 // otherwise poses problems when the aggregate is not
3643 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor);
3646 bool FrameView::hasCustomScrollbars() const
3648 for (auto& widget : children()) {
3649 if (is<FrameView>(*widget)) {
3650 if (downcast<FrameView>(*widget).hasCustomScrollbars())
3652 } else if (is<Scrollbar>(*widget)) {
3653 if (downcast<Scrollbar>(*widget).isCustomScrollbar())
3661 FrameView* FrameView::parentFrameView() const
3666 if (Frame* parentFrame = frame().tree().parent())
3667 return parentFrame->view();
3672 bool FrameView::isInChildFrameWithFrameFlattening() const
3674 if (!parent() || !frame().ownerElement())
3677 // Frame flattening applies when the owner element is either in a frameset or
3678 // an iframe with flattening parameters.
3679 if (is<HTMLIFrameElement>(*frame().ownerElement())) {
3680 RenderIFrame& iframeRenderer = downcast<RenderIFrame>(*frame().ownerElement()->renderWidget());
3681 if (iframeRenderer.flattenFrame())
3685 if (!frameFlatteningEnabled())
3688 if (is<HTMLFrameElement>(*frame().ownerElement()))
3694 void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree)
3696 // When we start a layout at the child level as opposed to the topmost frame view and this child
3697 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
3698 // will hit this view eventually.
3699 FrameView* parentView = parentFrameView();
3703 // In the middle of parent layout, no need to restart from topmost.
3704 if (parentView->m_nestedLayoutCount)
3707 // Parent tree is clean. Starting layout from it would have no effect.
3708 if (!parentView->needsLayout())
3711 while (parentView->parentFrameView())
3712 parentView = parentView->parentFrameView();
3714 parentView->layout(allowSubtree);
3716 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
3717 ASSERT_UNUSED(root, !root->needsLayout());
3720 void FrameView::updateControlTints()
3722 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
3723 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
3724 // This is only done if the theme supports control tinting. It's up to the theme and platform
3725 // to define when controls get the tint and to call this function when that changes.
3727 // Optimize the common case where we bring a window to the front while it's still empty.
3728 if (frame().document()->url().isEmpty())
3731 RenderView* renderView = this->renderView();
3732 if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars())
3733 paintControlTints();
3736 void FrameView::paintControlTints()
3741 GraphicsContext context((PlatformGraphicsContext*)nullptr);
3742 context.setUpdatingControlTints(true);
3743 if (platformWidget()) {
3744 // FIXME: consult paintsEntireContents().
3745 paintContents(&context, visibleContentRect(LegacyIOSDocumentVisibleRect));
3747 paint(&context, frameRect());
3750 bool FrameView::wasScrolledByUser() const
3752 return m_wasScrolledByUser;
3755 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
3757 if (m_inProgrammaticScroll)
3759 m_maintainScrollPositionAnchor = nullptr;
3760 if (m_wasScrolledByUser == wasScrolledByUser)
3762 m_wasScrolledByUser = wasScrolledByUser;
3763 if (frame().isMainFrame())
3764 updateLayerFlushThrottling();
3765 adjustTiledBackingCoverage();
3768 void FrameView::willPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3770 Document* document = frame().document();
3772 if (!context->paintingDisabled())
3773 InspectorInstrumentation::willPaint(renderView());
3775 paintingState.isTopLevelPainter = !sCurrentPaintTimeStamp;
3777 if (paintingState.isTopLevelPainter && MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
3778 LOG(MemoryPressure, "Under memory pressure: %s", WTF_PRETTY_FUNCTION);
3780 // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since
3781 // we might need some live bitmaps on painting.
3782 MemoryCache::singleton().prune();
3785 if (paintingState.isTopLevelPainter)
3786 sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
3788 paintingState.paintBehavior = m_paintBehavior;
3790 if (FrameView* parentView = parentFrameView()) {
3791 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
3792 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3795 if (m_paintBehavior == PaintBehaviorNormal)
3796 document->markers().invalidateRenderedRectsForMarkersInRect(dirtyRect);
3798 if (document->printing())
3799 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3801 paintingState.isFlatteningPaintOfRootFrame = (m_paintBehavior & PaintBehaviorFlattenCompositingLayers) && !frame().ownerElement();
3802 if (paintingState.isFlatteningPaintOfRootFrame)
3803 notifyWidgetsInAllFrames(WillPaintFlattened);
3805 ASSERT(!m_isPainting);
3806 m_isPainting = true;
3809 void FrameView::didPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3811 m_isPainting = false;
3813 if (paintingState.isFlatteningPaintOfRootFrame)
3814 notifyWidgetsInAllFrames(DidPaintFlattened);
3816 m_paintBehavior = paintingState.paintBehavior;
3817 m_lastPaintTime = monotonicallyIncreasingTime();
3819 // Painting can lead to decoding of large amounts of bitmaps
3820 // If we are low on memory, wipe them out after the paint.
3821 if (paintingState.isTopLevelPainter && MemoryPressureHandler::singleton().isUnderMemoryPressure())
3822 MemoryCache::singleton().pruneLiveResources(true);
3824 // Regions may have changed as a result of the visibility/z-index of element changing.
3825 #if ENABLE(DASHBOARD_SUPPORT)
3826 if (frame().document()->annotatedRegionsDirty())
3827 updateAnnotatedRegions();
3830 if (paintingState.isTopLevelPainter)
3831 sCurrentPaintTimeStamp = 0;
3833 if (!context->paintingDisabled()) {
3834 InspectorInstrumentation::didPaint(renderView(), dirtyRect);
3835 // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623
3836 firePaintRelatedMilestonesIfNeeded();
3840 void FrameView::paintContents(GraphicsContext* context, const IntRect& dirtyRect)
3842 if (m_layoutPhase == InViewSizeAdjust)
3845 ASSERT(m_layoutPhase == InPostLayerPositionsUpdatedAfterLayout || m_layoutPhase == OutsideLayout);
3849 if (frame().document()->printing())
3850 fillWithRed = false; // Printing, don't fill with red (can't remember why).
3851 else if (frame().ownerElement())
3852 fillWithRed = false; // Subframe, don't fill with red.
3853 else if (isTransparent())
3854 fillWithRed = false; // Transparent, don't fill with red.
3855 else if (m_paintBehavior & PaintBehaviorSelectionOnly)
3856 fillWithRed = false; // Selections are transparent, don't fill with red.
3857 else if (m_nodeToDraw)
3858 fillWithRed = false; // Element images are transparent, don't fill with red.
3863 context->fillRect(dirtyRect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
3866 RenderView* renderView = this->renderView();
3868 LOG_ERROR("called FrameView::paint with nil renderer");
3872 ASSERT(!needsLayout());
3876 PaintingState paintingState;
3877 willPaintContents(context, dirtyRect, paintingState);
3879 // m_nodeToDraw is used to draw only one element (and its descendants)
3880 RenderObject* renderer = m_nodeToDraw ? m_nodeToDraw->renderer() : nullptr;
3881 RenderLayer* rootLayer = renderView->layer();
3884 RenderElement::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(&rootLayer->renderer());
3887 // To work around http://webkit.org/b/135106, ensure that the paint root isn't an inline with culled line boxes.
3888 // FIXME: This can cause additional content to be included in the snapshot, so remove this once that bug is fixed.
3889 while (is<RenderInline>(renderer) && !downcast<RenderInline>(*renderer).firstLineBox())
3890 renderer = renderer->parent();
3892 rootLayer->paint(context, dirtyRect, LayoutSize(), m_paintBehavior, renderer);
3893 if (rootLayer->containsDirtyOverlayScrollbars())
3894 rootLayer->paintOverlayScrollbars(context, dirtyRect, m_paintBehavior, renderer);
3896 didPaintContents(context, dirtyRect, paintingState);
3899 void FrameView::setPaintBehavior(PaintBehavior behavior)
3901 m_paintBehavior = behavior;
3904 PaintBehavior FrameView::paintBehavior() const
3906 return m_paintBehavior;
3909 bool FrameView::isPainting() const
3911 return m_isPainting;
3914 // FIXME: change this to use the subtreePaint terminology.
3915 void FrameView::setNodeToDraw(Node* node)
3917 m_nodeToDraw = node;
3920 void FrameView::paintContentsForSnapshot(GraphicsContext* context, const IntRect& imageRect, SelectionInSnapshot shouldPaintSelection, CoordinateSpaceForSnapshot coordinateSpace)
3922 updateLayoutAndStyleIfNeededRecursive();
3924 // Cache paint behavior and set a new behavior appropriate for snapshots.
3925 PaintBehavior oldBehavior = paintBehavior();
3926 setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
3928 // If the snapshot should exclude selection, then we'll clear the current selection
3929 // in the render tree only. This will allow us to restore the selection from the DOM
3930 // after we paint the snapshot.
3931 if (shouldPaintSelection == ExcludeSelection) {
3932 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
3933 if (RenderView* root = frame->contentRenderer())
3934 root->clearSelection();
3938 if (coordinateSpace == DocumentCoordinates)
3939 paintContents(context, imageRect);
3941 // A snapshot in ViewCoordinates will include a scrollbar, and the snapshot will contain
3942 // whatever content the document is currently scrolled to.
3943 paint(context, imageRect);
3946 // Restore selection.
3947 if (shouldPaintSelection == ExcludeSelection) {
3948 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get()))
3949 frame->selection().updateAppearance();
3952 // Restore cached paint behavior.
3953 setPaintBehavior(oldBehavior);
3956 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
3958 if (context->paintingDisabled())
3961 if (frame().document()->printing())
3964 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
3967 void FrameView::updateLayoutAndStyleIfNeededRecursive()
3969 // We have to crawl our entire tree looking for any FrameViews that need
3970 // layout and make sure they are up to date.
3971 // Mac actually tests for intersection with the dirty region and tries not to
3972 // update layout for frames that are outside the dirty region. Not only does this seem
3973 // pointless (since those frames will have set a zero timer to layout anyway), but
3974 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
3975 // region but then become included later by the second frame adding rects to the dirty region
3976 // when it lays out.
3978 AnimationUpdateBlock animationUpdateBlock(&frame().animation());
3980 frame().document()->updateStyleIfNeeded();
3985 // Grab a copy of the children() set, as it may be mutated by the following updateLayoutAndStyleIfNeededRecursive
3986 // calls, as they can potentially re-enter a layout of the parent frame view, which may add/remove scrollbars
3987 // and thus mutates the children() set.
3988 // We use the Widget children because walking the Frame tree would include display:none frames.
3989 // FIXME: use FrameTree::traverseNextRendered().
3990 Vector<Ref<FrameView>, 16> childViews;
3991 childViews.reserveInitialCapacity(children().size());
3992 for (auto& widget : children()) {
3993 if (is<FrameView>(*widget))
3994 childViews.uncheckedAppend(downcast<FrameView>(*widget));
3997 for (unsigned i = 0; i < childViews.size(); ++i)
3998 childViews[i]->updateLayoutAndStyleIfNeededRecursive();
4000 // A child frame may have dirtied us during its layout.
4001 frame().document()->updateStyleIfNeeded();
4005 ASSERT(!frame().isMainFrame() || !needsStyleRecalcOrLayout());
4008 bool FrameView::qualifiesAsVisuallyNonEmpty() const
4011 Element* documentElement = frame().document()->documentElement();
4012 if (!documentElement || !documentElement->renderer())
4015 // Ensure that we always get marked visually non-empty eventually.
4016 if (!frame().document()->parsing() && frame().loader().stateMachine().committedFirstRealDocumentLoad())
4019 // Require the document to grow a bit.
4020 static const int documentHeightThreshold = 200;
4021 if (documentElement->renderBox()->layoutOverflowRect().pixelSnappedSize().height() < documentHeightThreshold)
4024 // The first few hundred characters rarely contain the interesting content of the page.
4025 if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold)
4027 // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout
4028 if (m_visuallyNonEmptyPixelCount > visualPixelThreshold)
4033 void FrameView::updateIsVisuallyNonEmpty()
4035 if (m_isVisuallyNonEmpty)
4037 if (!qualifiesAsVisuallyNonEmpty())
4039 m_isVisuallyNonEmpty = true;
4040 adjustTiledBackingCoverage();
4043 void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize)
4045 ASSERT(!enable || !minSize.isEmpty());
4046 ASSERT(minSize.width() <= maxSize.width());
4047 ASSERT(minSize.height() <= maxSize.height());
4049 if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize)
4052 m_shouldAutoSize = enable;
4053 m_minAutoSize = minSize;
4054 m_maxAutoSize = maxSize;
4055 m_didRunAutosize = false;
4059 if (m_shouldAutoSize)
4062 // Since autosize mode forces the scrollbar mode, change them to being auto.
4063 setVerticalScrollbarLock(false);
4064 setHorizontalScrollbarLock(false);
4065 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
4068 void FrameView::forceLayout(bool allowSubtree)
4070 layout(allowSubtree);
4073 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor, AdjustViewSizeOrNot shouldAdjustViewSize)
4075 // Dumping externalRepresentation(frame().renderer()).ascii() is a good trick to see
4076 // the state of things before and after the layout
4077 if (RenderView* renderView = this->renderView()) {
4078 float pageLogicalWidth = renderView->style().isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
4079 float pageLogicalHeight = renderView->style().isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
4081 renderView->setLogicalWidth(floor(pageLogicalWidth));
4082 renderView->setPageLogicalHeight(floor(pageLogicalHeight));
4083 renderView->setNeedsLayoutAndPrefWidthsRecalc();
4086 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
4087 // page width when shrunk, we will lay out at maximum shrink and clip extra content.
4088 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
4089 // implementation should not do this!
4090 bool horizontalWritingMode = renderView->style().isHorizontalWritingMode();
4091 const LayoutRect& documentRect = renderView->documentRect();
4092 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
4093 if (docLogicalWidth > pageLogicalWidth) {
4094 int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor);
4095 int expectedPageHeight = std::min<float>(documentRect.height(), pageSize.height() * maximumShrinkFactor);
4096 FloatSize maxPageSize = frame().resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), FloatSize(expectedPageWidth, expectedPageHeight));
4097 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
4098 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
4100 renderView->setLogicalWidth(floor(pageLogicalWidth));
4101 renderView->setPageLogicalHeight(floor(pageLogicalHeight));
4102 renderView->setNeedsLayoutAndPrefWidthsRecalc();
4105 const LayoutRect& updatedDocumentRect = renderView->documentRect();
4106 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
4107 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
4108 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
4109 LayoutUnit clippedLogicalLeft = 0;
4110 if (!renderView->style().isLeftToRightDirection())
4111 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
4112 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
4114 if (!horizontalWritingMode)
4115 overflow = overflow.transposedRect();
4116 renderView->clearLayoutOverflow();
4117 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
4121 if (shouldAdjustViewSize)
4125 void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/)
4127 RenderView* renderView = this->renderView();
4129 *newBottom = oldBottom;
4133 // Use a context with painting disabled.
4134 GraphicsContext context((PlatformGraphicsContext*)nullptr);
4135 renderView->setTruncatedAt(static_cast<int>(floorf(oldBottom)));
4136 IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), renderView->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop)));
4137 renderView->setPrintRect(dirtyRect);
4138 renderView->layer()->paint(&context, dirtyRect);
4139 *newBottom = renderView->bestTruncatedAt();
4141 *newBottom = oldBottom;
4142 renderView->setPrintRect(IntRect());
4145 IntRect FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntRect& rendererRect) const
4147 IntRect rect = snappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
4149 // Convert from page ("absolute") to FrameView coordinates.
4150 if (!delegatesScrolling())
4151 rect.moveBy(-scrollPosition() + IntPoint(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
4156 IntRect FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntRect& viewRect) const
4158 IntRect rect = viewRect;
4160 // Convert from FrameView coords into page ("absolute") coordinates.
4161 if (!delegatesScrolling())
4162 rect.moveBy(documentScrollPositionRelativeToViewOrigin());
4164 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
4165 // move the rect for now.
4166 rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms)));
4170 IntPoint FrameView::convertFromRendererToContainingView(const RenderElement* renderer, const IntPoint& rendererPoint) const
4172 IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms));
4174 // Convert from page ("absolute") to FrameView coordinates.
4175 if (!delegatesScrolling())
4176 point.moveBy(-scrollPosition() + IntPoint(0, headerHeight() + topContentInset(TopContentInsetType::WebCoreOrPlatformContentInset)));
4180 IntPoint FrameView::convertFromContainingViewToRenderer(const RenderElement* renderer, const IntPoint& viewPoint) const
4182 IntPoint point = viewPoint;
4184 // Convert from FrameView coords into page ("absolute") coordinates.
4185 if (!delegatesScrolling())
4186 point = point + documentScrollPositionRelativeToViewOrigin();
4188 return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms));
4191 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
4193 if (const ScrollView* parentScrollView = parent()) {
4194 if (is<FrameView>(*parentScrollView)) {
4195 const FrameView& parentView = downcast<FrameView>(*parentScrollView);
4196 // Get our renderer in the parent view
4197 RenderWidget* renderer = frame().ownerRenderer();
4201 IntRect rect(localRect);
4202 // Add borders and padding??
4203 rect.move(renderer->borderLeft() + renderer->paddingLeft(),
4204 renderer->borderTop() + renderer->paddingTop());
4205 return parentView.convertFromRendererToContainingView(renderer, rect);
4208 return Widget::convertToContainingView(localRect);
4214 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
4216 if (const ScrollView* parentScrollView = parent()) {
4217 if (is<FrameView>(*parentScrollView)) {
4218 const FrameView& parentView = downcast<FrameView>(*parentScrollView);
4220 // Get our renderer in the parent view
4221 RenderWidget* renderer = frame().ownerRenderer();
4225 IntRect rect = parentView.convertFromContainingViewToRenderer(renderer, parentRect);
4226 // Subtract borders and padding
4227 rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
4228 -renderer->borderTop() - renderer->paddingTop());
4232 return Widget::convertFromContainingView(parentRect);
4238 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
4240 if (const ScrollView* parentScrollView = parent()) {
4241 if (is<FrameView>(*parentScrollView)) {
4242 const FrameView& parentView = downcast<FrameView>(*parentScrollView);