2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Dirk Mueller <mueller@kde.org>
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9 * Copyright (C) 2009 Google Inc. All rights reserved.
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 "DocumentMarkerController.h"
39 #include "EventHandler.h"
40 #include "FloatRect.h"
41 #include "FocusController.h"
42 #include "FontCache.h"
43 #include "FontLoader.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameSelection.h"
47 #include "FrameTree.h"
48 #include "GraphicsContext.h"
49 #include "HTMLDocument.h"
50 #include "HTMLFrameElement.h"
51 #include "HTMLFrameSetElement.h"
52 #include "HTMLNames.h"
53 #include "HTMLPlugInImageElement.h"
54 #include "InspectorClient.h"
55 #include "InspectorController.h"
56 #include "InspectorInstrumentation.h"
58 #include "MainFrame.h"
59 #include "MemoryCache.h"
60 #include "MemoryPressureHandler.h"
61 #include "OverflowEvent.h"
62 #include "ProgressTracker.h"
63 #include "RenderEmbeddedObject.h"
64 #include "RenderFullScreen.h"
65 #include "RenderIFrame.h"
66 #include "RenderLayer.h"
67 #include "RenderLayerBacking.h"
68 #include "RenderLayerCompositor.h"
69 #include "RenderSVGRoot.h"
70 #include "RenderScrollbar.h"
71 #include "RenderScrollbarPart.h"
72 #include "RenderStyle.h"
73 #include "RenderText.h"
74 #include "RenderTheme.h"
75 #include "RenderView.h"
76 #include "RenderWidget.h"
77 #include "SVGDocument.h"
78 #include "SVGSVGElement.h"
79 #include "ScrollAnimator.h"
80 #include "ScrollingCoordinator.h"
82 #include "StyleResolver.h"
83 #include "TextResourceDecoder.h"
84 #include "TextStream.h"
85 #include "TiledBacking.h"
87 #include <wtf/CurrentTime.h>
89 #include <wtf/TemporaryChange.h>
91 #if USE(TILED_BACKING_STORE)
92 #include "TiledBackingStore.h"
95 #if ENABLE(TEXT_AUTOSIZING)
96 #include "TextAutosizer.h"
100 #include "DocumentLoader.h"
101 #include "LegacyTileCache.h"
102 #include "MemoryCache.h"
103 #include "MemoryPressureHandler.h"
104 #include "SystemMemory.h"
107 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
108 #include "HTMLMediaElement.h"
113 using namespace HTMLNames;
115 double FrameView::sCurrentPaintTimeStamp = 0.0;
117 // The maximum number of updateEmbeddedObjects iterations that should be done before returning.
118 static const unsigned maxUpdateEmbeddedObjectsIterations = 2;
120 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
122 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
123 if (didFullRepaint) {
124 flags &= ~RenderLayer::CheckForRepaint;
125 flags |= RenderLayer::NeedsFullRepaintInBacking;
127 if (isRelayoutingSubtree && (layer->isPaginated() || layer->enclosingPaginationLayer()))
128 flags |= RenderLayer::UpdatePagination;
132 Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style)
134 EOverflow overflow = style.overflowY();
135 if (overflow != OPAGEDX && overflow != OPAGEDY)
136 return Pagination::Unpaginated;
138 bool isHorizontalWritingMode = style.isHorizontalWritingMode();
139 TextDirection textDirection = style.direction();
140 WritingMode writingMode = style.writingMode();
142 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode
143 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode
144 // is vertical, then the direction of the verticality dictates the choice.
145 if (overflow == OPAGEDX) {
146 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode)
147 return Pagination::LeftToRightPaginated;
148 return Pagination::RightToLeftPaginated;
151 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode
152 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode
153 // is vertical, then we use TextDirection to choose between those options.
154 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL))
155 return Pagination::TopToBottomPaginated;
156 return Pagination::BottomToTopPaginated;
159 FrameView::FrameView(Frame& frame)
161 , m_canHaveScrollbars(true)
162 , m_layoutTimer(this, &FrameView::layoutTimerFired)
164 , m_layoutPhase(OutsideLayout)
165 , m_inSynchronousPostLayout(false)
166 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
167 , m_isTransparent(false)
168 , m_baseBackgroundColor(Color::white)
169 , m_mediaType("screen")
170 , m_overflowStatusDirty(true)
171 , m_viewportRenderer(0)
172 , m_wasScrolledByUser(false)
173 , m_inProgrammaticScroll(false)
174 , m_safeToPropagateScrollToParent(true)
175 , m_isTrackingRepaints(false)
176 , m_shouldUpdateWhileOffscreen(true)
177 , m_exposedRect(FloatRect::infiniteRect())
178 , m_deferSetNeedsLayouts(0)
179 , m_setNeedsLayoutWasDeferred(false)
180 , m_speculativeTilingEnabled(false)
181 , m_speculativeTilingEnableTimer(this, &FrameView::speculativeTilingEnableTimerFired)
183 , m_useCustomFixedPositionLayoutRect(false)
185 , m_hasOverrideViewportSize(false)
186 , m_shouldAutoSize(false)
187 , m_inAutoSize(false)
188 , m_didRunAutosize(false)
189 , m_autoSizeFixedMinimumHeight(0)
192 , m_milestonesPendingPaint(0)
193 , m_visualUpdatesAllowedByClient(true)
194 , m_scrollPinningBehavior(DoNotPin)
198 if (frame.isMainFrame()) {
199 ScrollableArea::setVerticalScrollElasticity(m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed);
200 ScrollableArea::setHorizontalScrollElasticity(m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed);
204 PassRefPtr<FrameView> FrameView::create(Frame& frame)
206 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
208 return view.release();
211 PassRefPtr<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
213 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
214 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
216 return view.release();
219 FrameView::~FrameView()
221 if (m_postLayoutTasksTimer.isActive())
222 m_postLayoutTasksTimer.stop();
224 removeFromAXObjectCache();
227 // Custom scrollbars should already be destroyed at this point
228 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
229 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
231 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
232 setHasVerticalScrollbar(false);
234 ASSERT(!m_scrollCorner);
236 ASSERT(frame().view() != this || !frame().contentRenderer());
239 void FrameView::reset()
241 m_cannotBlitToWindow = false;
242 m_isOverlapped = false;
243 m_contentIsOpaque = false;
246 m_layoutTimer.stop();
248 m_delayedLayout = false;
249 m_needsFullRepaint = true;
250 m_layoutSchedulingEnabled = true;
251 m_layoutPhase = OutsideLayout;
252 m_inSynchronousPostLayout = false;
254 m_nestedLayoutCount = 0;
255 m_postLayoutTasksTimer.stop();
256 m_firstLayout = true;
257 m_firstLayoutCallbackPending = false;
258 m_wasScrolledByUser = false;
259 m_safeToPropagateScrollToParent = true;
260 m_lastViewportSize = IntSize();
261 m_lastZoomFactor = 1.0f;
262 m_isTrackingRepaints = false;
263 m_trackedRepaintRects.clear();
265 m_paintBehavior = PaintBehaviorNormal;
266 m_isPainting = false;
267 m_visuallyNonEmptyCharacterCount = 0;
268 m_visuallyNonEmptyPixelCount = 0;
269 m_isVisuallyNonEmpty = false;
270 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
271 m_maintainScrollPositionAnchor = 0;
274 void FrameView::removeFromAXObjectCache()
276 if (AXObjectCache* cache = axObjectCache())
280 void FrameView::resetScrollbars()
282 // Reset the document's scrollbars back to our defaults before we yield the floor.
283 m_firstLayout = true;
284 setScrollbarsSuppressed(true);
285 if (m_canHaveScrollbars)
286 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
288 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
289 setScrollbarsSuppressed(false);
292 void FrameView::resetScrollbarsAndClearContentsSize()
296 setScrollbarsSuppressed(true);
297 setContentsSize(IntSize());
298 setScrollbarsSuppressed(false);
301 void FrameView::init()
305 m_margins = LayoutSize(-1, -1); // undefined
306 m_size = LayoutSize();
308 // Propagate the marginwidth/height and scrolling modes to the view.
309 Element* ownerElement = frame().ownerElement();
310 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
311 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
312 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
313 setCanHaveScrollbars(false);
314 LayoutUnit marginWidth = frameElt->marginWidth();
315 LayoutUnit marginHeight = frameElt->marginHeight();
316 if (marginWidth != -1)
317 setMarginWidth(marginWidth);
318 if (marginHeight != -1)
319 setMarginHeight(marginHeight);
322 Page* page = frame().page();
323 if (page && page->chrome().client().shouldPaintEntireContents())
324 setPaintsEntireContents(true);
327 void FrameView::prepareForDetach()
329 detachCustomScrollbars();
330 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
331 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
332 removeFromAXObjectCache();
334 if (frame().page()) {
335 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
336 scrollingCoordinator->willDestroyScrollableArea(this);
340 void FrameView::detachCustomScrollbars()
342 Scrollbar* horizontalBar = horizontalScrollbar();
343 if (horizontalBar && horizontalBar->isCustomScrollbar())
344 setHasHorizontalScrollbar(false);
346 Scrollbar* verticalBar = verticalScrollbar();
347 if (verticalBar && verticalBar->isCustomScrollbar())
348 setHasVerticalScrollbar(false);
350 m_scrollCorner = nullptr;
353 void FrameView::recalculateScrollbarOverlayStyle()
355 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
356 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
358 Color backgroundColor = documentBackgroundColor();
359 if (backgroundColor.isValid()) {
360 // Reduce the background color from RGB to a lightness value
361 // and determine which scrollbar style to use based on a lightness
363 double hue, saturation, lightness;
364 backgroundColor.getHSL(hue, saturation, lightness);
365 if (lightness <= .5 && backgroundColor.alpha() > 0)
366 overlayStyle = ScrollbarOverlayStyleLight;
369 if (oldOverlayStyle != overlayStyle)
370 setScrollbarOverlayStyle(overlayStyle);
373 void FrameView::clear()
375 setCanBlitOnScroll(true);
379 setScrollbarsSuppressed(true);
382 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
383 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
384 if (LegacyTileCache* tileCache = legacyTileCache())
385 tileCache->setTilingMode(LegacyTileCache::Disabled);
389 bool FrameView::didFirstLayout() const
391 return !m_firstLayout;
394 void FrameView::invalidateRect(const IntRect& rect)
397 if (HostWindow* window = hostWindow())
398 window->invalidateContentsAndRootView(rect);
402 RenderWidget* renderer = frame().ownerRenderer();
406 IntRect repaintRect = rect;
407 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
408 renderer->borderTop() + renderer->paddingTop());
409 renderer->repaintRectangle(repaintRect);
412 void FrameView::setFrameRect(const IntRect& newRect)
414 IntRect oldRect = frameRect();
415 if (newRect == oldRect)
418 #if ENABLE(TEXT_AUTOSIZING)
419 // Autosized font sizes depend on the width of the viewing area.
420 if (newRect.width() != oldRect.width()) {
421 Page* page = frame().page();
422 if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) {
423 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
424 frame().document()->textAutosizer()->recalculateMultipliers();
429 ScrollView::setFrameRect(newRect);
431 updateScrollableAreaSet();
433 if (RenderView* renderView = this->renderView()) {
434 if (renderView->usesCompositing())
435 renderView->compositor().frameViewDidChangeSize();
438 if (!frameFlatteningEnabled())
439 sendResizeEventIfNeeded();
442 #if ENABLE(REQUEST_ANIMATION_FRAME)
443 bool FrameView::scheduleAnimation()
445 if (HostWindow* window = hostWindow()) {
446 window->scheduleAnimation();
453 void FrameView::setMarginWidth(LayoutUnit w)
455 // make it update the rendering area when set
456 m_margins.setWidth(w);
459 void FrameView::setMarginHeight(LayoutUnit h)
461 // make it update the rendering area when set
462 m_margins.setHeight(h);
465 bool FrameView::frameFlatteningEnabled() const
467 return frame().settings().frameFlatteningEnabled();
470 bool FrameView::isFrameFlatteningValidForThisFrame() const
472 if (!frameFlatteningEnabled())
475 HTMLFrameOwnerElement* owner = frame().ownerElement();
479 // Frame flattening is valid only for <frame> and <iframe>.
480 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
483 bool FrameView::avoidScrollbarCreation() const
485 // with frame flattening no subframe can have scrollbars
486 // but we also cannot turn scrollbars off as we determine
487 // our flattening policy using that.
488 return isFrameFlatteningValidForThisFrame();
491 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
493 m_canHaveScrollbars = canHaveScrollbars;
494 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
497 void FrameView::updateCanHaveScrollbars()
501 scrollbarModes(hMode, vMode);
502 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
503 setCanHaveScrollbars(false);
505 setCanHaveScrollbars(true);
508 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
510 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
511 return ScrollView::createScrollbar(orientation);
513 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
514 Document* doc = frame().document();
516 // Try the <body> element first as a scrollbar source.
517 Element* body = doc ? doc->body() : 0;
518 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
519 return RenderScrollbar::createCustomScrollbar(this, orientation, body);
521 // If the <body> didn't have a custom style, then the root element might.
522 Element* docElement = doc ? doc->documentElement() : 0;
523 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
524 return RenderScrollbar::createCustomScrollbar(this, orientation, docElement);
526 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
527 RenderWidget* frameRenderer = frame().ownerRenderer();
528 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
529 return RenderScrollbar::createCustomScrollbar(this, orientation, 0, &frame());
531 // Nobody set a custom style, so we just use a native scrollbar.
532 return ScrollView::createScrollbar(orientation);
535 void FrameView::setContentsSize(const IntSize& size)
537 if (size == contentsSize())
540 m_deferSetNeedsLayouts++;
542 ScrollView::setContentsSize(size);
543 ScrollView::contentsResized();
545 Page* page = frame().page();
549 updateScrollableAreaSet();
551 page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
553 ASSERT(m_deferSetNeedsLayouts);
554 m_deferSetNeedsLayouts--;
556 if (!m_deferSetNeedsLayouts)
557 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
560 void FrameView::adjustViewSize()
562 RenderView* renderView = this->renderView();
566 ASSERT(frame().view() == this);
568 const IntRect rect = renderView->documentRect();
569 const IntSize& size = rect.size();
570 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
572 setContentsSize(size);
575 void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
577 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
578 // overflow:hidden and overflow:scroll on <body> as applying to the document's
579 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
580 // use the root element.
582 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
583 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
586 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
588 EOverflow overflowX = o->style().overflowX();
589 EOverflow overflowY = o->style().overflowY();
591 if (o->isSVGRoot()) {
592 // overflow is ignored in stand-alone SVG documents.
593 if (!toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument())
602 hMode = ScrollbarAuto;
604 hMode = ScrollbarAlwaysOff;
607 hMode = ScrollbarAlwaysOn;
610 hMode = ScrollbarAuto;
613 // Don't set it at all.
620 vMode = ScrollbarAuto;
622 vMode = ScrollbarAlwaysOff;
625 vMode = ScrollbarAlwaysOn;
628 vMode = ScrollbarAuto;
631 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
635 m_viewportRenderer = o;
638 void FrameView::applyPaginationToViewport()
640 Document* document = frame().document();
641 auto documentElement = document->documentElement();
642 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
643 RenderElement* documentOrBodyRenderer = documentRenderer;
644 auto body = document->body();
645 if (body && body->renderer()) {
646 if (body->hasTagName(bodyTag))
647 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer;
650 Pagination pagination;
652 if (!documentOrBodyRenderer) {
653 setPagination(pagination);
657 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
658 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
659 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
660 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
663 setPagination(pagination);
666 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
668 m_viewportRenderer = 0;
670 const HTMLFrameOwnerElement* owner = frame().ownerElement();
671 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
672 hMode = ScrollbarAlwaysOff;
673 vMode = ScrollbarAlwaysOff;
677 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
678 hMode = ScrollbarAuto;
679 vMode = ScrollbarAuto;
681 hMode = ScrollbarAlwaysOff;
682 vMode = ScrollbarAlwaysOff;
686 Document* document = frame().document();
687 auto documentElement = document->documentElement();
688 RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr;
689 auto body = document->body();
690 if (body && body->renderer()) {
691 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
692 vMode = ScrollbarAlwaysOff;
693 hMode = ScrollbarAlwaysOff;
694 } else if (body->hasTagName(bodyTag)) {
695 // It's sufficient to just check the X overflow,
696 // since it's illegal to have visible in only one direction.
697 RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
698 applyOverflowToViewport(o, hMode, vMode);
700 } else if (rootRenderer)
701 applyOverflowToViewport(rootRenderer, hMode, vMode);
705 void FrameView::updateCompositingLayersAfterStyleChange()
707 RenderView* renderView = this->renderView();
711 // If we expect to update compositing after an incipient layout, don't do so here.
712 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
715 RenderLayerCompositor& compositor = renderView->compositor();
716 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
717 compositor.cacheAcceleratedCompositingFlags();
718 compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange);
721 void FrameView::updateCompositingLayersAfterLayout()
723 RenderView* renderView = this->renderView();
727 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
728 renderView->compositor().cacheAcceleratedCompositingFlags();
729 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
732 void FrameView::clearBackingStores()
734 RenderView* renderView = this->renderView();
738 RenderLayerCompositor& compositor = renderView->compositor();
739 ASSERT(compositor.inCompositingMode());
740 compositor.enableCompositingMode(false);
741 compositor.clearBackingForAllLayers();
744 void FrameView::restoreBackingStores()
746 RenderView* renderView = this->renderView();
750 RenderLayerCompositor& compositor = renderView->compositor();
751 compositor.enableCompositingMode(true);
752 compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
755 bool FrameView::usesCompositedScrolling() const
757 RenderView* renderView = this->renderView();
760 if (frame().settings().compositedScrollingForFramesEnabled())
761 return renderView->compositor().inForcedCompositingMode();
765 GraphicsLayer* FrameView::layerForScrolling() const
767 RenderView* renderView = this->renderView();
770 return renderView->compositor().scrollLayer();
773 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
775 RenderView* renderView = this->renderView();
778 return renderView->compositor().layerForHorizontalScrollbar();
781 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
783 RenderView* renderView = this->renderView();
786 return renderView->compositor().layerForVerticalScrollbar();
789 GraphicsLayer* FrameView::layerForScrollCorner() const
791 RenderView* renderView = this->renderView();
794 return renderView->compositor().layerForScrollCorner();
797 TiledBacking* FrameView::tiledBacking() const
799 RenderView* renderView = this->renderView();
803 RenderLayerBacking* backing = renderView->layer()->backing();
807 return backing->graphicsLayer()->tiledBacking();
810 uint64_t FrameView::scrollLayerID() const
812 RenderView* renderView = this->renderView();
816 RenderLayerBacking* backing = renderView->layer()->backing();
820 return backing->scrollingNodeID();
823 ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
825 RenderView* renderView = this->renderView();
829 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
832 #if ENABLE(RUBBER_BANDING)
833 GraphicsLayer* FrameView::layerForOverhangAreas() const
835 RenderView* renderView = this->renderView();
838 return renderView->compositor().layerForOverhangAreas();
841 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
843 RenderView* renderView = this->renderView();
847 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
850 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
852 RenderView* renderView = this->renderView();
856 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
859 #endif // ENABLE(RUBBER_BANDING)
861 bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush)
863 RenderView* renderView = this->renderView();
865 return true; // We don't want to keep trying to update layers if we have no renderer.
867 ASSERT(frame().view() == this);
869 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
870 // layer content to occur before layout has happened, which will cause paintContents() to bail.
875 if (LegacyTileCache* tileCache = legacyTileCache())
876 tileCache->doPendingRepaints();
879 renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame());
884 void FrameView::setNeedsOneShotDrawingSynchronization()
886 if (Page* page = frame().page())
887 page->chrome().client().setNeedsOneShotDrawingSynchronization();
890 GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
892 // To find the Widget that corresponds with platformWidget we have to do a linear
893 // search of our child widgets.
894 Widget* foundWidget = nullptr;
895 for (auto& widget : children()) {
896 if (widget->platformWidget() != platformWidget)
898 foundWidget = widget.get();
905 auto* renderWidget = RenderWidget::find(foundWidget);
909 RenderLayer* widgetLayer = renderWidget->layer();
910 if (!widgetLayer || !widgetLayer->isComposited())
913 return widgetLayer->backing()->parentForSublayers();
916 void FrameView::scheduleLayerFlushAllowingThrottling()
918 RenderView* view = this->renderView();
921 view->compositor().scheduleLayerFlush(true /* canThrottle */);
924 void FrameView::setHeaderHeight(int headerHeight)
927 ASSERT(frame().isMainFrame());
928 m_headerHeight = headerHeight;
930 if (RenderView* renderView = this->renderView())
931 renderView->setNeedsLayout();
934 void FrameView::setFooterHeight(int footerHeight)
937 ASSERT(frame().isMainFrame());
938 m_footerHeight = footerHeight;
940 if (RenderView* renderView = this->renderView())
941 renderView->setNeedsLayout();
944 float FrameView::topContentInset() const
946 if (!frame().isMainFrame())
949 Page* page = frame().page();
950 return page ? page->topContentInset() : 0;
953 void FrameView::topContentInsetDidChange()
955 RenderView* renderView = this->renderView();
961 updateScrollbars(scrollOffset());
962 if (renderView->usesCompositing())
963 renderView->compositor().frameViewDidChangeSize();
966 bool FrameView::hasCompositedContent() const
968 if (RenderView* renderView = this->renderView())
969 return renderView->compositor().inCompositingMode();
973 bool FrameView::hasCompositedContentIncludingDescendants() const
975 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
976 RenderView* renderView = frame->contentRenderer();
977 if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : 0) {
978 if (compositor->inCompositingMode())
981 if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this))
988 bool FrameView::hasCompositingAncestor() const
990 for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) {
991 if (FrameView* view = frame->view()) {
992 if (view->hasCompositedContent())
999 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
1000 void FrameView::enterCompositingMode()
1002 if (RenderView* renderView = this->renderView()) {
1003 renderView->compositor().enableCompositingMode();
1005 renderView->compositor().scheduleCompositingLayerUpdate();
1009 bool FrameView::isEnclosedInCompositingLayer() const
1011 auto frameOwnerRenderer = frame().ownerRenderer();
1012 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1015 if (FrameView* parentView = parentFrameView())
1016 return parentView->isEnclosedInCompositingLayer();
1020 bool FrameView::flushCompositingStateIncludingSubframes()
1022 bool allFramesFlushed = flushCompositingStateForThisFrame(&frame());
1024 for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) {
1025 bool flushed = child->view()->flushCompositingStateForThisFrame(&frame());
1026 allFramesFlushed &= flushed;
1028 return allFramesFlushed;
1031 bool FrameView::isSoftwareRenderable() const
1033 RenderView* renderView = this->renderView();
1034 return !renderView || !renderView->compositor().has3DContent();
1037 void FrameView::didMoveOnscreen()
1039 contentAreaDidShow();
1042 void FrameView::willMoveOffscreen()
1044 contentAreaDidHide();
1047 void FrameView::setIsInWindow(bool isInWindow)
1049 if (RenderView* renderView = this->renderView())
1050 renderView->setIsInWindow(isInWindow);
1053 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
1055 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
1058 inline void FrameView::forceLayoutParentViewIfNeeded()
1060 RenderWidget* ownerRenderer = frame().ownerRenderer();
1064 RenderBox* contentBox = embeddedContentBox();
1068 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
1069 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
1072 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1073 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1074 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
1075 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1076 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1077 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1078 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1079 Ref<FrameView> frameView(ownerRenderer->view().frameView());
1081 // Mark the owner renderer as needing layout.
1082 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1084 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
1085 frameView->layout();
1088 void FrameView::layout(bool allowSubtree)
1093 // Protect the view from being deleted during layout (in recalcStyle).
1094 Ref<FrameView> protect(*this);
1096 // Many of the tasks performed during layout can cause this function to be re-entered,
1097 // so save the layout phase now and restore it on exit.
1098 TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1100 // Every scroll that happens during layout is programmatic.
1101 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1103 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1105 if (inChildFrameLayoutWithFrameFlattening) {
1106 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1107 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1108 if (!root || !root->needsLayout())
1113 if (updateFixedPositionLayoutRect())
1114 allowSubtree = false;
1117 m_layoutTimer.stop();
1118 m_delayedLayout = false;
1119 m_setNeedsLayoutWasDeferred = false;
1121 // we shouldn't enter layout() while painting
1122 ASSERT(!isPainting());
1126 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(&frame());
1128 if (!allowSubtree && m_layoutRoot) {
1129 m_layoutRoot->markContainingBlocksForLayout(false);
1133 ASSERT(frame().view() == this);
1134 ASSERT(frame().document());
1136 Document& document = *frame().document();
1137 ASSERT(!document.inPageCache());
1140 RenderElement* root;
1143 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1145 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1146 // This is a new top-level layout. If there are any remaining tasks from the previous
1147 // layout, finish them now.
1148 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1149 performPostLayoutTasks();
1152 m_layoutPhase = InPreLayoutStyleUpdate;
1154 // Viewport-dependent media queries may cause us to need completely different style information.
1155 StyleResolver* styleResolver = document.styleResolverIfExists();
1156 if (!styleResolver || styleResolver->affectedByViewportChange()) {
1157 document.styleResolverChanged(DeferRecalcStyle);
1158 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1159 InspectorInstrumentation::mediaQueryResultChanged(&document);
1161 document.evaluateMediaQueryList();
1163 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1164 // take care of that now.
1165 applyPaginationToViewport();
1167 // Always ensure our style info is up-to-date. This can happen in situations where
1168 // the layout beats any sort of style recalc update that needs to occur.
1169 document.updateStyleIfNeeded();
1170 m_layoutPhase = InPreLayout;
1172 subtree = m_layoutRoot;
1174 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1175 // so there's no point to continuing to layout
1179 root = subtree ? m_layoutRoot : document.renderView();
1181 // FIXME: Do we need to set m_size here?
1185 // Close block here so we can set up the font cache purge preventer, which we will still
1186 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1187 // The next block sets m_layoutSchedulingEnabled back to false once again.
1190 FontCachePurgePreventer fontCachePurgePreventer;
1193 ++m_nestedLayoutCount;
1196 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1198 if (!m_layoutRoot) {
1199 HTMLElement* body = document.body();
1200 if (body && body->renderer()) {
1201 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
1202 body->renderer()->setChildNeedsLayout();
1203 } else if (body->hasTagName(bodyTag)) {
1204 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox()->stretchesToViewport())
1205 body->renderer()->setChildNeedsLayout();
1209 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1210 if (m_firstLayout && !frame().ownerElement())
1211 printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count());
1215 autoSizeIfEnabled();
1217 m_needsFullRepaint = !subtree && (m_firstLayout || toRenderView(*root).printing());
1220 ScrollbarMode hMode;
1221 ScrollbarMode vMode;
1222 calculateScrollbarModesForLayout(hMode, vMode);
1224 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1225 if (m_firstLayout) {
1226 setScrollbarsSuppressed(true);
1228 m_firstLayout = false;
1229 m_firstLayoutCallbackPending = true;
1230 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
1231 m_lastViewportSize = fixedLayoutSize();
1233 m_lastViewportSize = visibleContentRectIncludingScrollbars().size();
1235 m_lastZoomFactor = root->style().zoom();
1237 // Set the initial vMode to AlwaysOn if we're auto.
1238 if (vMode == ScrollbarAuto)
1239 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1240 // Set the initial hMode to AlwaysOff if we're auto.
1241 if (hMode == ScrollbarAuto)
1242 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1244 setScrollbarModes(hMode, vMode);
1245 setScrollbarsSuppressed(false, true);
1247 setScrollbarModes(hMode, vMode);
1250 LayoutSize oldSize = m_size;
1252 m_size = layoutSize();
1254 if (oldSize != m_size) {
1255 m_needsFullRepaint = true;
1256 if (!m_firstLayout) {
1257 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : 0;
1258 RenderBox* bodyRenderer = rootRenderer && document.body() ? document.body()->renderBox() : 0;
1259 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1260 bodyRenderer->setChildNeedsLayout();
1261 else if (rootRenderer && rootRenderer->stretchesToViewport())
1262 rootRenderer->setChildNeedsLayout();
1266 m_layoutPhase = InPreLayout;
1269 layer = root->enclosingLayer();
1271 bool disableLayoutState = false;
1273 disableLayoutState = root->view().shouldDisableLayoutStateForSubtree(root);
1274 root->view().pushLayoutState(*root);
1276 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? &root->view() : 0);
1277 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1279 ASSERT(m_layoutPhase == InPreLayout);
1280 m_layoutPhase = InLayout;
1282 forceLayoutParentViewIfNeeded();
1284 ASSERT(m_layoutPhase == InLayout);
1287 #if ENABLE(IOS_TEXT_AUTOSIZING)
1288 float minZoomFontSize = frame().settings().minimumZoomFontSize();
1289 float visWidth = frame().page()->textAutosizingWidth();
1290 if (minZoomFontSize && visWidth && !root->view().printing()) {
1291 root->adjustComputedFontSizesOnBlocks(minZoomFontSize, visWidth);
1292 bool needsLayout = root->needsLayout();
1297 #if ENABLE(TEXT_AUTOSIZING)
1298 if (document.textAutosizer()->processSubtree(root) && root->needsLayout())
1302 ASSERT(m_layoutPhase == InLayout);
1305 root->view().popLayoutState(*root);
1309 // Close block here to end the scope of changeSchedulingEnabled and layoutStateDisabler.
1312 m_layoutPhase = InViewSizeAdjust;
1314 bool neededFullRepaint = m_needsFullRepaint;
1316 if (!subtree && !toRenderView(*root).printing())
1319 m_layoutPhase = InPostLayout;
1321 m_needsFullRepaint = neededFullRepaint;
1323 // Now update the positions of all layers.
1324 if (m_needsFullRepaint)
1325 root->view().repaintRootContents();
1327 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1329 updateCompositingLayersAfterLayout();
1333 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1334 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1335 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1338 #if ENABLE(DASHBOARD_SUPPORT)
1339 updateAnnotatedRegions();
1342 #if ENABLE(IOS_TOUCH_EVENTS)
1343 document.dirtyTouchEventRects();
1346 ASSERT(!root->needsLayout());
1348 updateCanBlitOnScrollRecursively();
1350 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1351 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1353 if (!m_postLayoutTasksTimer.isActive()) {
1354 if (!m_inSynchronousPostLayout) {
1355 if (inChildFrameLayoutWithFrameFlattening)
1356 updateWidgetPositions();
1358 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1359 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1363 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1364 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1365 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1366 // can make us need to update again, and we can get stuck in a nasty cycle unless
1367 // we call it through the timer here.
1368 m_postLayoutTasksTimer.startOneShot(0);
1374 InspectorInstrumentation::didLayout(cookie, root);
1376 --m_nestedLayoutCount;
1379 RenderBox* FrameView::embeddedContentBox() const
1381 RenderView* renderView = this->renderView();
1385 RenderObject* firstChild = renderView->firstChild();
1386 if (!firstChild || !firstChild->isBox())
1389 // Curently only embedded SVG documents participate in the size-negotiation logic.
1390 if (toRenderBox(firstChild)->isSVGRoot())
1391 return toRenderBox(firstChild);
1396 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1398 if (!m_embeddedObjectsToUpdate)
1399 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1401 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1402 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
1403 // Tell the DOM element that it needs a widget update.
1404 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
1405 if (!pluginElement.needsCheckForSizeChange())
1406 pluginElement.setNeedsWidgetUpdate(true);
1409 m_embeddedObjectsToUpdate->add(&embeddedObject);
1412 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1414 if (!m_embeddedObjectsToUpdate)
1417 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1420 void FrameView::setMediaType(const String& mediaType)
1422 m_mediaType = mediaType;
1425 String FrameView::mediaType() const
1427 // See if we have an override type.
1428 String overrideType = frame().loader().client().overrideMediaType();
1429 InspectorInstrumentation::applyEmulatedMedia(&frame(), &overrideType);
1430 if (!overrideType.isNull())
1431 return overrideType;
1435 void FrameView::adjustMediaTypeForPrinting(bool printing)
1438 if (m_mediaTypeWhenNotPrinting.isNull())
1439 m_mediaTypeWhenNotPrinting = mediaType();
1440 setMediaType("print");
1442 if (!m_mediaTypeWhenNotPrinting.isNull())
1443 setMediaType(m_mediaTypeWhenNotPrinting);
1444 m_mediaTypeWhenNotPrinting = String();
1448 bool FrameView::useSlowRepaints(bool considerOverlap) const
1450 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1452 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1453 // m_contentIsOpaque, so don't take the fast path for composited layers
1454 // if they are a platform widget in order to get painting correctness
1455 // for transparent layers. See the comment in WidgetMac::paint.
1456 if (contentsInCompositedLayer() && !platformWidget())
1459 bool isOverlapped = m_isOverlapped && considerOverlap;
1461 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1464 if (FrameView* parentView = parentFrameView())
1465 return parentView->useSlowRepaints(considerOverlap);
1470 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1472 return useSlowRepaints(false);
1475 void FrameView::updateCanBlitOnScrollRecursively()
1477 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1478 if (FrameView* view = frame->view())
1479 view->setCanBlitOnScroll(!view->useSlowRepaints());
1483 bool FrameView::contentsInCompositedLayer() const
1485 RenderView* renderView = this->renderView();
1486 if (renderView && renderView->isComposited()) {
1487 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1488 if (layer && layer->drawsContent())
1495 void FrameView::setCannotBlitToWindow()
1497 m_cannotBlitToWindow = true;
1498 updateCanBlitOnScrollRecursively();
1501 void FrameView::addSlowRepaintObject(RenderElement* o)
1503 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1505 if (!m_slowRepaintObjects)
1506 m_slowRepaintObjects = std::make_unique<HashSet<RenderElement*>>();
1508 m_slowRepaintObjects->add(o);
1510 if (!hadSlowRepaintObjects) {
1511 updateCanBlitOnScrollRecursively();
1513 if (Page* page = frame().page()) {
1514 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1515 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1520 void FrameView::removeSlowRepaintObject(RenderElement* o)
1522 if (!m_slowRepaintObjects)
1525 m_slowRepaintObjects->remove(o);
1526 if (m_slowRepaintObjects->isEmpty()) {
1527 m_slowRepaintObjects = nullptr;
1528 updateCanBlitOnScrollRecursively();
1530 if (Page* page = frame().page()) {
1531 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1532 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1537 void FrameView::addViewportConstrainedObject(RenderElement* object)
1539 if (!m_viewportConstrainedObjects)
1540 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1542 if (!m_viewportConstrainedObjects->contains(object)) {
1543 m_viewportConstrainedObjects->add(object);
1544 if (platformWidget())
1545 updateCanBlitOnScrollRecursively();
1547 if (Page* page = frame().page()) {
1548 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1549 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1554 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1556 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1557 if (Page* page = frame().page()) {
1558 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1559 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1562 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1563 // why isn't the same check being made here?
1564 updateCanBlitOnScrollRecursively();
1568 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1571 if (useCustomFixedPositionLayoutRect())
1572 return customFixedPositionLayoutRect();
1574 LayoutRect viewportRect = visibleContentRect();
1576 viewportRect.setLocation(toLayoutPoint(scrollOffsetForFixedPosition()));
1577 return viewportRect;
1580 LayoutRect FrameView::viewportConstrainedExtentRect() const
1583 if (platformWidget())
1584 return visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
1586 return renderView()->unscaledDocumentRect();
1588 return viewportConstrainedVisibleContentRect();
1592 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)
1594 LayoutPoint position;
1595 if (behaviorForFixed == StickToDocumentBounds)
1596 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1598 position = scrollPosition;
1599 position.setY(position.y() - headerHeight);
1602 LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
1604 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1605 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1607 return LayoutSize(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1610 LayoutSize FrameView::scrollOffsetForFixedPosition() const
1612 IntRect visibleContentRect = this->visibleContentRect();
1613 IntSize totalContentsSize = this->totalContentsSize();
1614 IntPoint scrollPosition = this->scrollPosition();
1615 IntPoint scrollOrigin = this->scrollOrigin();
1616 float frameScaleFactor = frame().frameScaleFactor();
1617 ScrollBehaviorForFixedElements behaviorForFixed = scrollBehaviorForFixedElements();
1618 return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), behaviorForFixed, headerHeight(), footerHeight());
1622 LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
1624 if (fixedElementsLayoutRelativeToFrame)
1625 return visibleContentRect;
1627 // We impose an lower limit on the size (so an upper limit on the scale) of
1628 // the rect used to position fixed objects so that they don't crowd into the
1629 // center of the screen at larger scales.
1630 const float constraintThresholdScale = 1.2;
1632 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
1634 LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
1636 if (frameScaleFactor > constraintThresholdScale) {
1637 FloatRect contentRect(FloatPoint(), totalContentsSize);
1638 FloatRect viewportRect = visibleContentRect;
1640 // Scale the rect up from a point that is relative to its position in the viewport.
1641 FloatSize sizeDelta = contentRect.size() - viewportRect.size();
1643 FloatPoint scaleOrigin;
1644 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
1645 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
1647 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
1648 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
1649 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
1651 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
1654 if (scrollBehavior == StickToDocumentBounds) {
1655 LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
1656 viewportConstrainedObjectsRect.intersect(documentBounds);
1659 return viewportConstrainedObjectsRect;
1662 LayoutRect FrameView::viewportConstrainedObjectsRect() const
1664 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
1668 IntPoint FrameView::minimumScrollPosition() const
1670 IntPoint minimumPosition(ScrollView::minimumScrollPosition());
1672 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
1673 minimumPosition.setY(maximumScrollPosition().y());
1675 return minimumPosition;
1678 IntPoint FrameView::maximumScrollPosition() const
1680 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
1682 maximumOffset.clampNegativeToZero();
1684 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
1685 maximumOffset.setY(minimumScrollPosition().y());
1687 return maximumOffset;
1690 bool FrameView::fixedElementsLayoutRelativeToFrame() const
1692 return frame().settings().fixedElementsLayoutRelativeToFrame();
1695 IntPoint FrameView::lastKnownMousePosition() const
1697 return frame().eventHandler().lastKnownMousePosition();
1700 bool FrameView::isHandlingWheelEvent() const
1702 return frame().eventHandler().isHandlingWheelEvent();
1705 bool FrameView::shouldSetCursor() const
1707 Page* page = frame().page();
1708 return page && page->isVisible() && page->focusController().isActive();
1711 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1713 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1714 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1718 const bool isCompositedContentLayer = contentsInCompositedLayer();
1720 // Get the rects of the fixed objects visible in the rectToScroll
1721 Region regionToUpdate;
1722 for (auto& renderer : *m_viewportConstrainedObjects) {
1723 if (!renderer->style().hasViewportConstrainedPosition())
1725 if (renderer->isComposited())
1728 // Fixed items should always have layers.
1729 ASSERT(renderer->hasLayer());
1730 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1732 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1733 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1734 // Don't invalidate for invisible fixed layers.
1738 #if ENABLE(CSS_FILTERS)
1739 if (layer->hasAncestorWithFilterOutsets()) {
1740 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1741 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1745 IntRect updateRect = pixelSnappedIntRect(layer->repaintRectIncludingNonCompositingDescendants());
1746 updateRect = contentsToRootView(updateRect);
1747 if (!isCompositedContentLayer && clipsRepaints())
1748 updateRect.intersect(rectToScroll);
1749 if (!updateRect.isEmpty())
1750 regionToUpdate.unite(updateRect);
1754 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1756 // 2) update the area of fixed objects that has been invalidated
1757 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1758 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1759 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1760 IntRect updateRect = subRectsToUpdate[i];
1761 IntRect scrolledRect = updateRect;
1762 scrolledRect.move(scrollDelta);
1763 updateRect.unite(scrolledRect);
1764 if (isCompositedContentLayer) {
1765 updateRect = rootViewToContents(updateRect);
1766 ASSERT(renderView());
1767 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1770 if (clipsRepaints())
1771 updateRect.intersect(rectToScroll);
1772 hostWindow()->invalidateContentsAndRootView(updateRect);
1778 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1780 if (contentsInCompositedLayer()) {
1781 // FIXME: respect paintsEntireContents()?
1782 IntRect updateRect = visibleContentRect(LegacyIOSDocumentVisibleRect);
1784 // Make sure to "apply" the scale factor here since we're converting from frame view
1785 // coordinates to layer backing coordinates.
1786 updateRect.scale(1 / frame().frameScaleFactor());
1788 ASSERT(renderView());
1789 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect, GraphicsLayer::DoNotClipToLayer);
1792 repaintSlowRepaintObjects();
1794 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
1795 if (isEnclosedInCompositingLayer()) {
1796 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1797 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1798 visibleWidth(), visibleHeight());
1799 frameRenderer->repaintRectangle(rect);
1804 ScrollView::scrollContentsSlowPath(updateRect);
1807 void FrameView::repaintSlowRepaintObjects()
1809 if (!m_slowRepaintObjects)
1812 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
1813 // repaint them after scrolling.
1814 for (auto& renderer : *m_slowRepaintObjects)
1815 renderer->repaintSlowRepaintObject();
1818 // Note that this gets called at painting time.
1819 void FrameView::setIsOverlapped(bool isOverlapped)
1821 if (isOverlapped == m_isOverlapped)
1824 m_isOverlapped = isOverlapped;
1825 updateCanBlitOnScrollRecursively();
1827 if (hasCompositedContentIncludingDescendants()) {
1828 // Overlap can affect compositing tests, so if it changes, we need to trigger
1829 // a layer update in the parent document.
1830 if (Frame* parentFrame = frame().tree().parent()) {
1831 if (RenderView* parentView = parentFrame->contentRenderer()) {
1832 RenderLayerCompositor& compositor = parentView->compositor();
1833 compositor.setCompositingLayersNeedRebuild();
1834 compositor.scheduleCompositingLayerUpdate();
1838 if (RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) {
1839 // We also need to trigger reevaluation for this and all descendant frames,
1840 // since a frame uses compositing if any ancestor is compositing.
1841 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1842 if (RenderView* view = frame->contentRenderer()) {
1843 RenderLayerCompositor& compositor = view->compositor();
1844 compositor.setCompositingLayersNeedRebuild();
1845 compositor.scheduleCompositingLayerUpdate();
1852 bool FrameView::isOverlappedIncludingAncestors() const
1857 if (FrameView* parentView = parentFrameView()) {
1858 if (parentView->isOverlapped())
1865 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1867 if (contentIsOpaque == m_contentIsOpaque)
1870 m_contentIsOpaque = contentIsOpaque;
1871 updateCanBlitOnScrollRecursively();
1874 void FrameView::restoreScrollbar()
1876 setScrollbarsSuppressed(false);
1879 bool FrameView::scrollToFragment(const URL& url)
1881 // If our URL has no ref, then we have no place we need to jump to.
1882 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1883 // and possibly repaint because :target pseudo class may have been
1884 // set (see bug 11321).
1885 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
1888 String fragmentIdentifier = url.fragmentIdentifier();
1889 if (scrollToAnchor(fragmentIdentifier))
1892 // Try again after decoding the ref, based on the document's encoding.
1893 if (TextResourceDecoder* decoder = frame().document()->decoder())
1894 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
1899 bool FrameView::scrollToAnchor(const String& name)
1901 ASSERT(frame().document());
1903 if (!frame().document()->haveStylesheetsLoaded()) {
1904 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1908 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1910 Element* anchorElement = frame().document()->findAnchor(name);
1912 // Setting to null will clear the current target.
1913 frame().document()->setCSSTarget(anchorElement);
1915 if (frame().document()->isSVGDocument()) {
1916 if (SVGSVGElement* svg = toSVGDocument(frame().document())->rootElement()) {
1917 svg->setupInitialView(name, anchorElement);
1923 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1924 if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1927 maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : frame().document());
1929 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1930 if (anchorElement && anchorElement->isFocusable())
1931 frame().document()->setFocusedElement(anchorElement);
1936 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1938 m_maintainScrollPositionAnchor = anchorNode;
1939 if (!m_maintainScrollPositionAnchor)
1942 // We need to update the layout before scrolling, otherwise we could
1943 // really mess things up if an anchor scroll comes at a bad moment.
1944 frame().document()->updateStyleIfNeeded();
1945 // Only do a layout if changes have occurred that make it necessary.
1946 RenderView* renderView = this->renderView();
1947 if (renderView && renderView->needsLayout())
1953 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1955 frame().document()->updateLayoutIgnorePendingStylesheets();
1957 LayoutRect bounds = element->boundingBox();
1958 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
1959 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
1960 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
1963 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1965 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1966 m_maintainScrollPositionAnchor = 0;
1967 ScrollView::setScrollPosition(scrollPoint);
1970 void FrameView::delegatesScrollingDidChange()
1972 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
1973 if (hasCompositedContent())
1974 clearBackingStores();
1977 #if USE(TILED_BACKING_STORE)
1978 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
1980 bool visibleContentSizeDidChange = false;
1981 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
1982 // When the viewport size changes or the content is scaled, we need to
1983 // reposition the fixed and sticky positioned elements.
1984 setViewportConstrainedObjectsNeedLayout();
1985 visibleContentSizeDidChange = true;
1988 IntSize offset = scrollOffset();
1989 IntPoint oldPosition = scrollPosition();
1990 ScrollView::setFixedVisibleContentRect(visibleContentRect);
1991 if (offset != scrollOffset()) {
1992 updateLayerPositionsAfterScrolling();
1993 if (frame().page()->settings().acceleratedCompositingForFixedPositionEnabled())
1994 updateCompositingLayersAfterScrolling();
1995 IntPoint newPosition = scrollPosition();
1996 scrollAnimator()->setCurrentPosition(scrollPosition());
1997 scrollPositionChanged(oldPosition, newPosition);
1999 if (visibleContentSizeDidChange) {
2000 // Update the scroll-bars to calculate new page-step size.
2001 updateScrollbars(scrollOffset());
2003 frame().loader().client().didChangeScrollOffset();
2007 void FrameView::setViewportConstrainedObjectsNeedLayout()
2009 if (!hasViewportConstrainedObjects())
2012 for (auto& renderer : *m_viewportConstrainedObjects)
2013 renderer->setNeedsLayout();
2016 void FrameView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition)
2018 updateLayerPositionsAfterScrolling();
2019 updateCompositingLayersAfterScrolling();
2020 repaintSlowRepaintObjects();
2021 scrollPositionChanged(oldPosition, newPosition);
2024 void FrameView::scrollPositionChanged(const IntPoint& oldPosition, const IntPoint& newPosition)
2026 frame().eventHandler().sendScrollEvent();
2027 frame().eventHandler().dispatchFakeMouseMoveEventSoon();
2029 if (Document* document = frame().document())
2030 document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize());
2032 if (RenderView* renderView = this->renderView()) {
2033 renderView->resumePausedImageAnimationsIfNeeded();
2034 if (renderView->usesCompositing())
2035 renderView->compositor().frameViewDidScroll();
2039 void FrameView::updateLayerPositionsAfterScrolling()
2041 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2042 if (m_layoutPhase == InViewSizeAdjust)
2045 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2046 if (RenderView* renderView = this->renderView()) {
2047 updateWidgetPositions();
2048 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2053 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2055 #if ENABLE(ASYNC_SCROLLING)
2056 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2058 Page* page = frame().page();
2062 if (&page->mainFrame() != &frame())
2065 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2066 if (!scrollingCoordinator)
2069 if (!scrollingCoordinator->supportsFixedPositionLayers())
2072 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2075 if (inProgrammaticScroll())
2083 void FrameView::updateCompositingLayersAfterScrolling()
2085 if (!shouldUpdateCompositingLayersAfterScrolling())
2088 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2089 if (RenderView* renderView = this->renderView())
2090 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2094 bool FrameView::isRubberBandInProgress() const
2096 if (scrollbarsSuppressed())
2099 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2100 // ScrollingCoordinator::isRubberBandInProgress().
2101 if (Page* page = frame().page()) {
2102 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2103 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2104 return scrollingCoordinator->isRubberBandInProgress();
2108 // If the main thread updates the scroll position for this FrameView, we should return
2109 // ScrollAnimator::isRubberBandInProgress().
2110 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2111 return scrollAnimator->isRubberBandInProgress();
2116 bool FrameView::requestScrollPositionUpdate(const IntPoint& position)
2118 #if ENABLE(ASYNC_SCROLLING)
2119 if (TiledBacking* tiledBacking = this->tiledBacking()) {
2120 IntRect visibleRect = visibleContentRect();
2121 visibleRect.setLocation(position);
2122 tiledBacking->prepopulateRect(visibleRect);
2125 if (Page* page = frame().page()) {
2126 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2127 return scrollingCoordinator->requestScrollPositionUpdate(this, position);
2130 UNUSED_PARAM(position);
2136 HostWindow* FrameView::hostWindow() const
2138 if (Page* page = frame().page())
2139 return &page->chrome();
2143 void FrameView::addTrackedRepaintRect(const FloatRect& r)
2145 if (!m_isTrackingRepaints || r.isEmpty())
2148 FloatRect repaintRect = r;
2149 repaintRect.move(-scrollOffset());
2150 m_trackedRepaintRects.append(repaintRect);
2153 void FrameView::repaintContentRectangle(const IntRect& r)
2155 ASSERT(!frame().ownerElement());
2157 if (!shouldUpdate())
2160 #if USE(TILED_BACKING_STORE)
2161 if (frame().tiledBackingStore()) {
2162 frame().tiledBackingStore()->invalidate(r);
2166 ScrollView::repaintContentRectangle(r);
2169 static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderObject& renderer, unsigned countSoFar, unsigned threshold)
2171 // FIXME: Consider writing this using RenderObject::nextInPreOrder() instead of using recursion.
2172 if (renderer.isText())
2173 countSoFar += toRenderText(renderer).text()->length();
2175 for (RenderObject* child = renderer.firstChildSlow(); child; child = child->nextSibling()) {
2176 if (countSoFar >= threshold)
2178 countSoFar = countRenderedCharactersInRenderObjectWithThreshold(*child, countSoFar, threshold);
2183 bool FrameView::renderedCharactersExceed(unsigned threshold)
2185 if (!m_frame->contentRenderer())
2187 return countRenderedCharactersInRenderObjectWithThreshold(*m_frame->contentRenderer(), 0, threshold) >= threshold;
2190 void FrameView::contentsResized()
2192 ScrollView::contentsResized();
2196 void FrameView::fixedLayoutSizeChanged()
2198 // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized().
2199 // An ASSERT is triggered when a view schedules a layout before being attached to a frame.
2200 if (!frame().view())
2202 ScrollView::fixedLayoutSizeChanged();
2205 bool FrameView::shouldLayoutAfterContentsResized() const
2207 return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2210 void FrameView::visibleContentsResized()
2212 // We check to make sure the view is attached to a frame() as this method can
2213 // be triggered before the view is attached by Frame::createView(...) setting
2214 // various values such as setScrollBarModes(...) for example. An ASSERT is
2215 // triggered when a view is layout before being attached to a frame().
2216 if (!frame().view())
2220 if (RenderView* root = m_frame->contentRenderer()) {
2221 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2222 setViewportConstrainedObjectsNeedLayout();
2223 // We must eagerly enter compositing mode because fixed position elements
2224 // will not have been made compositing via a preceding style change before
2225 // m_useCustomFixedPositionLayoutRect was true.
2226 root->compositor().enableCompositingMode();
2231 if (shouldLayoutAfterContentsResized() && needsLayout())
2234 if (RenderView* renderView = this->renderView()) {
2235 if (renderView->usesCompositing())
2236 renderView->compositor().frameViewDidChangeSize();
2240 void FrameView::addedOrRemovedScrollbar()
2242 if (RenderView* renderView = this->renderView()) {
2243 if (renderView->usesCompositing())
2244 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2248 void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2250 if (RenderView* view = renderView())
2251 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2254 void FrameView::updateLayerFlushThrottlingInAllFrames()
2256 bool isMainLoadProgressing = frame().page()->progress().isMainLoadProgressing();
2257 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2258 if (RenderView* renderView = frame->contentRenderer())
2259 renderView->compositor().setLayerFlushThrottlingEnabled(isMainLoadProgressing);
2263 void FrameView::adjustTiledBackingCoverage()
2265 if (!m_speculativeTilingEnabled)
2266 enableSpeculativeTilingIfNeeded();
2268 RenderView* renderView = this->renderView();
2269 if (renderView && renderView->layer()->backing())
2270 renderView->layer()->backing()->adjustTiledBackingCoverage();
2272 if (LegacyTileCache* tileCache = legacyTileCache())
2273 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2277 static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2279 return view.isVisuallyNonEmpty() && !view.frame().page()->progress().isMainLoadProgressing();
2282 void FrameView::enableSpeculativeTilingIfNeeded()
2284 ASSERT(!m_speculativeTilingEnabled);
2285 if (m_wasScrolledByUser) {
2286 m_speculativeTilingEnabled = true;
2289 if (!shouldEnableSpeculativeTilingDuringLoading(*this))
2291 if (m_speculativeTilingEnableTimer.isActive())
2293 // Delay enabling a bit as load completion may trigger further loading from scripts.
2294 static const double speculativeTilingEnableDelay = 0.5;
2295 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
2298 void FrameView::speculativeTilingEnableTimerFired(Timer<FrameView>&)
2300 if (m_speculativeTilingEnabled)
2302 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
2303 adjustTiledBackingCoverage();
2306 void FrameView::layoutTimerFired(Timer<FrameView>&)
2308 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2309 if (!frame().document()->ownerElement())
2310 printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count());
2315 void FrameView::scheduleRelayout()
2317 // FIXME: We should assert the page is not in the page cache, but that is causing
2318 // too many false assertions. See <rdar://problem/7218118>.
2319 ASSERT(frame().view() == this);
2322 m_layoutRoot->markContainingBlocksForLayout(false);
2325 if (!m_layoutSchedulingEnabled)
2329 if (!frame().document()->shouldScheduleLayout())
2331 InspectorInstrumentation::didInvalidateLayout(&frame());
2332 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2333 // Also invalidate parent frame starting from the owner element of this frame.
2334 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2335 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2337 std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay();
2338 if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count())
2339 unscheduleRelayout();
2340 if (m_layoutTimer.isActive())
2343 m_delayedLayout = delay.count();
2345 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2346 if (!frame().document()->ownerElement())
2347 printf("Scheduling layout for %d\n", delay);
2350 m_layoutTimer.startOneShot(delay);
2353 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2355 for (RenderObject* r = descendant; r; r = r->container()) {
2362 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2364 ASSERT(renderView());
2365 RenderView& renderView = *this->renderView();
2367 // Try to catch unnecessary work during render tree teardown.
2368 ASSERT(!renderView.documentBeingDestroyed());
2369 ASSERT(frame().view() == this);
2371 if (renderView.needsLayout()) {
2372 newRelayoutRoot.markContainingBlocksForLayout(false);
2376 if (!layoutPending() && m_layoutSchedulingEnabled) {
2377 std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay();
2378 ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout());
2379 m_layoutRoot = &newRelayoutRoot;
2380 InspectorInstrumentation::didInvalidateLayout(&frame());
2381 m_delayedLayout = delay.count();
2382 m_layoutTimer.startOneShot(delay);
2386 if (m_layoutRoot == &newRelayoutRoot)
2389 if (!m_layoutRoot) {
2390 // Just relayout the subtree.
2391 newRelayoutRoot.markContainingBlocksForLayout(false);
2392 InspectorInstrumentation::didInvalidateLayout(&frame());
2396 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2397 // Keep the current root.
2398 newRelayoutRoot.markContainingBlocksForLayout(false, m_layoutRoot);
2399 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2403 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2404 // Re-root at newRelayoutRoot.
2405 m_layoutRoot->markContainingBlocksForLayout(false, &newRelayoutRoot);
2406 m_layoutRoot = &newRelayoutRoot;
2407 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2408 InspectorInstrumentation::didInvalidateLayout(&frame());
2412 // Just do a full relayout.
2413 m_layoutRoot->markContainingBlocksForLayout(false);
2415 newRelayoutRoot.markContainingBlocksForLayout(false);
2416 InspectorInstrumentation::didInvalidateLayout(&frame());
2419 bool FrameView::layoutPending() const
2421 return m_layoutTimer.isActive();
2424 bool FrameView::needsLayout() const
2426 // This can return true in cases where the document does not have a body yet.
2427 // Document::shouldScheduleLayout takes care of preventing us from scheduling
2428 // layout in that case.
2429 RenderView* renderView = this->renderView();
2430 return layoutPending()
2431 || (renderView && renderView->needsLayout())
2433 || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
2436 void FrameView::setNeedsLayout()
2438 if (m_deferSetNeedsLayouts) {
2439 m_setNeedsLayoutWasDeferred = true;
2443 if (RenderView* renderView = this->renderView())
2444 renderView->setNeedsLayout();
2447 void FrameView::unscheduleRelayout()
2449 if (!m_layoutTimer.isActive())
2452 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2453 if (!frame().document()->ownerElement())
2454 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
2457 m_layoutTimer.stop();
2458 m_delayedLayout = false;
2461 #if ENABLE(REQUEST_ANIMATION_FRAME)
2462 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
2464 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
2465 frame->view()->serviceScrollAnimations();
2466 frame->animation().serviceAnimations();
2469 Vector<RefPtr<Document>> documents;
2470 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext())
2471 documents.append(frame->document());
2473 for (size_t i = 0; i < documents.size(); ++i)
2474 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
2478 bool FrameView::isTransparent() const
2480 return m_isTransparent;
2483 void FrameView::setTransparent(bool isTransparent)
2485 m_isTransparent = isTransparent;
2488 bool FrameView::hasOpaqueBackground() const
2490 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
2493 Color FrameView::baseBackgroundColor() const
2495 return m_baseBackgroundColor;
2498 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
2500 if (!backgroundColor.isValid())
2501 m_baseBackgroundColor = Color::white;
2503 m_baseBackgroundColor = backgroundColor;
2505 recalculateScrollbarOverlayStyle();
2508 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
2510 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2511 if (FrameView* view = frame->view()) {
2512 view->setTransparent(transparent);
2513 view->setBaseBackgroundColor(backgroundColor);
2518 void FrameView::setBackgroundExtendsBeyondPage(bool extendBackground)
2520 RenderView* renderView = this->renderView();
2524 renderView->compositor().setRootExtendedBackgroundColor(extendBackground ? documentBackgroundColor() : Color());
2525 setHasExtendedBackgroundRectForPainting(needsExtendedBackgroundRectForPainting());
2528 bool FrameView::hasExtendedBackgroundRectForPainting() const
2530 if (!frame().settings().backgroundShouldExtendBeyondPage())
2533 TiledBacking* tiledBacking = this->tiledBacking();
2537 return tiledBacking->hasMargins();
2540 bool FrameView::needsExtendedBackgroundRectForPainting() const
2542 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
2543 // that the background rect needs to be extended for painting. Simple backgrounds can be extended
2544 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
2545 // such as images, require extending the background rect to continue painting into the extended
2546 // region. This function finds out if it is necessary to extend the background rect for painting.
2549 // <rdar://problem/16201373>
2553 if (!frame().settings().backgroundShouldExtendBeyondPage())
2556 if (!frame().isMainFrame())
2559 Document* document = frame().document();
2563 auto documentElement = document->documentElement();
2564 auto bodyElement = document->body();
2565 auto documentElementRenderer = documentElement ? documentElement->renderer() : nullptr;
2566 auto bodyRenderer = bodyElement ? bodyElement->renderer() : nullptr;
2567 bool rootBackgroundHasImage = (documentElementRenderer && documentElementRenderer->style().hasBackgroundImage())
2568 || (bodyRenderer && bodyRenderer->style().hasBackgroundImage());
2570 return rootBackgroundHasImage;
2573 void FrameView::setHasExtendedBackgroundRectForPainting(bool shouldHaveExtendedBackgroundRect)
2575 if (shouldHaveExtendedBackgroundRect == hasExtendedBackgroundRectForPainting())
2578 RenderView* renderView = this->renderView();
2582 RenderLayerBacking* backing = renderView->layer()->backing();
2586 backing->setTiledBackingHasMargins(frame().settings().backgroundShouldExtendBeyondPage() && shouldHaveExtendedBackgroundRect);
2589 IntRect FrameView::extendedBackgroundRectForPainting() const
2591 TiledBacking* tiledBacking = this->tiledBacking();
2595 RenderView* renderView = this->renderView();
2599 LayoutRect extendedRect = renderView->unextendedBackgroundRect(renderView);
2600 if (!tiledBacking->hasMargins())
2601 return pixelSnappedIntRect(extendedRect);
2603 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
2604 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
2605 return pixelSnappedIntRect(extendedRect);
2608 bool FrameView::shouldUpdateWhileOffscreen() const
2610 return m_shouldUpdateWhileOffscreen;
2613 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
2615 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
2618 bool FrameView::shouldUpdate() const
2620 if (isOffscreen() && !shouldUpdateWhileOffscreen())
2625 void FrameView::scrollToAnchor()
2627 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
2631 if (!anchorNode->renderer())
2635 if (anchorNode != frame().document())
2636 rect = anchorNode->boundingBox();
2638 // Scroll nested layers and frames to reveal the anchor.
2639 // Align to the top and to the closest side (this matches other browsers).
2640 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
2642 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
2643 cache->handleScrolledToAnchor(anchorNode.get());
2645 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
2646 m_maintainScrollPositionAnchor = anchorNode;
2649 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
2651 // No need to update if it's already crashed or known to be missing.
2652 if (embeddedObject.isPluginUnavailable())
2655 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
2657 if (embeddedObject.isSnapshottedPlugIn()) {
2658 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
2659 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2660 pluginElement.checkSnapshotStatus();
2665 auto weakRenderer = embeddedObject.createWeakPtr();
2667 // FIXME: This could turn into a real virtual dispatch if we defined
2668 // updateWidget(PluginCreationOption) on HTMLElement.
2669 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element) || isHTMLAppletElement(element)) {
2670 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2671 if (pluginElement.needsCheckForSizeChange()) {
2672 pluginElement.checkSnapshotStatus();
2675 if (pluginElement.needsWidgetUpdate())
2676 pluginElement.updateWidget(CreateAnyWidgetType);
2679 // FIXME: It is not clear that Media elements need or want this updateWidget() call.
2680 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2681 else if (element.isMediaElement())
2682 toHTMLMediaElement(element).updateWidget(CreateAnyWidgetType);
2685 ASSERT_NOT_REACHED();
2687 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
2691 embeddedObject.updateWidgetPosition();
2694 bool FrameView::updateEmbeddedObjects()
2696 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
2699 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
2701 // Insert a marker for where we should stop.
2702 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
2703 m_embeddedObjectsToUpdate->add(nullptr);
2705 while (!m_embeddedObjectsToUpdate->isEmpty()) {
2706 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
2707 if (!embeddedObject)
2709 updateEmbeddedObject(*embeddedObject);
2712 return m_embeddedObjectsToUpdate->isEmpty();
2715 void FrameView::flushAnyPendingPostLayoutTasks()
2717 if (!m_postLayoutTasksTimer.isActive())
2720 performPostLayoutTasks();
2723 void FrameView::performPostLayoutTasks()
2725 m_postLayoutTasksTimer.stop();
2727 frame().selection().setCaretRectNeedsUpdate();
2728 frame().selection().updateAndRevealSelection();
2730 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
2731 fireLayoutRelatedMilestonesIfNeeded();
2734 // Only send layout-related delegate callbacks synchronously for the main frame to
2735 // avoid re-entering layout for the main frame while delivering a layout-related delegate
2736 // callback for a subframe.
2737 if (frame().isMainFrame())
2738 frame().page()->chrome().client().didLayout();
2741 #if ENABLE(FONT_LOAD_EVENTS)
2742 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
2743 frame().document()->fontloader()->didLayout();
2746 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
2747 // with didLayout(LayoutMilestones).
2748 frame().loader().client().dispatchDidLayout();
2750 updateWidgetPositions();
2752 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
2753 // is called through the post layout timer.
2754 Ref<FrameView> protect(*this);
2756 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
2757 if (updateEmbeddedObjects())
2761 if (auto* page = frame().page()) {
2762 if (auto* scrollingCoordinator = page->scrollingCoordinator())
2763 scrollingCoordinator->frameViewLayoutUpdated(this);
2766 if (RenderView* renderView = this->renderView()) {
2767 if (renderView->usesCompositing())
2768 renderView->compositor().frameViewDidLayout();
2773 sendResizeEventIfNeeded();
2776 void FrameView::sendResizeEventIfNeeded()
2778 RenderView* renderView = this->renderView();
2779 if (!renderView || renderView->printing())
2781 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
2784 IntSize currentSize;
2785 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
2786 currentSize = fixedLayoutSize();
2788 currentSize = visibleContentRectIncludingScrollbars().size();
2790 float currentZoomFactor = renderView->style().zoom();
2791 bool shouldSendResizeEvent = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor);
2793 m_lastViewportSize = currentSize;
2794 m_lastZoomFactor = currentZoomFactor;
2796 if (!shouldSendResizeEvent)
2800 // Don't send the resize event if the document is loading. Some pages automatically reload
2801 // when the window is resized; Safari on iOS often resizes the window while setting up its
2802 // viewport. This obviously can cause problems.
2803 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
2804 if (documentLoader->isLoadingInAPISense())
2809 bool isMainFrame = frame().isMainFrame();
2810 bool canSendResizeEventSynchronously = !m_shouldAutoSize && isMainFrame && !isInLayout();
2812 // If we resized during layout, queue up a resize event for later, otherwise fire it right away.
2813 RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
2814 if (canSendResizeEventSynchronously)
2815 frame().document()->dispatchWindowEvent(resizeEvent.release(), frame().document()->domWindow());
2817 frame().document()->enqueueWindowEvent(resizeEvent.release());
2819 #if ENABLE(INSPECTOR)
2820 Page* page = frame().page();
2821 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
2822 if (InspectorClient* inspectorClient = page ? page->inspectorController().inspectorClient() : nullptr)
2823 inspectorClient->didResizeMainFrame(&frame());
2828 void FrameView::willStartLiveResize()
2830 ScrollView::willStartLiveResize();
2831 adjustTiledBackingCoverage();
2834 void FrameView::willEndLiveResize()
2836 ScrollView::willEndLiveResize();
2837 adjustTiledBackingCoverage();
2840 void FrameView::postLayoutTimerFired(Timer<FrameView>&)
2842 performPostLayoutTasks();
2845 void FrameView::autoSizeIfEnabled()
2847 if (!m_shouldAutoSize)
2853 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2855 Document* document = frame().document();
2859 RenderView* documentView = document->renderView();
2860 Element* documentElement = document->documentElement();
2861 if (!documentView || !documentElement)
2864 // Start from the minimum size and allow it to grow.
2865 resize(m_minAutoSize.width(), m_minAutoSize.height());
2867 IntSize size = frameRect().size();
2869 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2870 // which may result in a height change during the second iteration.
2871 for (int i = 0; i < 2; i++) {
2872 // Update various sizes including contentsSize, scrollHeight, etc.
2873 document->updateLayoutIgnorePendingStylesheets();
2874 int width = documentView->minPreferredLogicalWidth();
2875 int height = documentView->documentRect().height();
2876 IntSize newSize(width, height);
2878 // Check to see if a scrollbar is needed for a given dimension and
2879 // if so, increase the other dimension to account for the scrollbar.
2880 // Since the dimensions are only for the view rectangle, once a
2881 // dimension exceeds the maximum, there is no need to increase it further.
2882 if (newSize.width() > m_maxAutoSize.width()) {
2883 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2884 if (!localHorizontalScrollbar)
2885 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2886 if (!localHorizontalScrollbar->isOverlayScrollbar())
2887 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
2889 // Don't bother checking for a vertical scrollbar because the width is at
2890 // already greater the maximum.
2891 } else if (newSize.height() > m_maxAutoSize.height()) {
2892 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
2893 if (!localVerticalScrollbar)
2894 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
2895 if (!localVerticalScrollbar->isOverlayScrollbar())
2896 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
2898 // Don't bother checking for a horizontal scrollbar because the height is
2899 // already greater the maximum.
2902 // Ensure the size is at least the min bounds.
2903 newSize = newSize.expandedTo(m_minAutoSize);
2905 // Bound the dimensions by the max bounds and determine what scrollbars to show.
2906 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
2907 if (newSize.width() > m_maxAutoSize.width()) {
2908 newSize.setWidth(m_maxAutoSize.width());
2909 horizonalScrollbarMode = ScrollbarAlwaysOn;
2911 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
2912 if (newSize.height() > m_maxAutoSize.height()) {
2913 newSize.setHeight(m_maxAutoSize.height());
2914 verticalScrollbarMode = ScrollbarAlwaysOn;
2917 if (newSize == size)
2920 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
2921 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
2922 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
2923 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
2926 resize(newSize.width(), newSize.height());
2927 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
2928 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
2929 setVerticalScrollbarLock(false);
2930 setHorizontalScrollbarLock(false);
2931 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
2934 m_autoSizeContentSize = contentsSize();
2936 if (m_autoSizeFixedMinimumHeight) {
2937 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
2938 document->updateLayoutIgnorePendingStylesheets();
2941 m_didRunAutosize = true;
2944 void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
2946 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
2949 m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
2954 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2956 if (!m_viewportRenderer)
2959 if (m_overflowStatusDirty) {
2960 m_horizontalOverflow = horizontalOverflow;
2961 m_verticalOverflow = verticalOverflow;
2962 m_overflowStatusDirty = false;
2966 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2967 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2969 if (horizontalOverflowChanged || verticalOverflowChanged) {
2970 m_horizontalOverflow = horizontalOverflow;
2971 m_verticalOverflow = verticalOverflow;
2973 RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
2974 verticalOverflowChanged, verticalOverflow);
2975 overflowEvent->setTarget(m_viewportRenderer->element());
2977 frame().document()->enqueueOverflowEvent(overflowEvent.release());
2982 const Pagination& FrameView::pagination() const
2984 if (m_pagination != Pagination())
2985 return m_pagination;
2987 if (frame().isMainFrame())
2988 return frame().page()->pagination();
2990 return m_pagination;
2993 void FrameView::setPagination(const Pagination& pagination)
2995 if (m_pagination == pagination)
2998 m_pagination = pagination;
3000 frame().document()->styleResolverChanged(DeferRecalcStyle);
3003 IntRect FrameView::windowClipRect(bool clipToContents) const
3005 ASSERT(frame().view() == this);
3007 if (paintsEntireContents())
3008 return IntRect(IntPoint(), totalContentsSize());
3010 // Set our clip rect to be our contents.
3013 clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect));
3015 clipRect = contentsToWindow(visibleContentRectIncludingScrollbars(LegacyIOSDocumentVisibleRect));
3016 if (!frame().ownerElement())
3019 // Take our owner element and get its clip rect.
3020 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
3021 if (FrameView* parentView = ownerElement->document().view())
3022 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
3026 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
3028 // The renderer can sometimes be null when style="display:none" interacts
3029 // with external content and plugins.
3030 if (!ownerElement->renderer())
3031 return windowClipRect();
3033 // If we have no layer, just return our window clip rect.
3034 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
3035 if (!enclosingLayer)
3036 return windowClipRect();
3038 // Apply the clip from the layer.
3040 if (clipToLayerContents)
3041 clipRect = pixelSnappedIntRect(enclosingLayer->childrenClipRect());
3043 clipRect = pixelSnappedIntRect(enclosingLayer->selfClipRect());
3044 clipRect = contentsToWindow(clipRect);
3045 return intersection(clipRect, windowClipRect());
3048 bool FrameView::isActive() const
3050 Page* page = frame().page();
3051 return page && page->focusController().isActive();
3054 bool FrameView::updatesScrollLayerPositionOnMainThread() const
3056 if (Page* page = frame().page()) {
3057 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
3058 return scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously();
3064 void FrameView::scrollTo(const IntSize& newOffset)
3066 LayoutSize offset = scrollOffset();
3067 IntPoint oldPosition = scrollPosition();
3068 ScrollView::scrollTo(newOffset);
3069 if (offset != scrollOffset())
3070 scrollPositionChanged(oldPosition, scrollPosition());
3071 frame().loader().client().didChangeScrollOffset();
3074 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
3076 // Add in our offset within the FrameView.
3077 IntRect dirtyRect = rect;
3078 dirtyRect.moveBy(scrollbar->location());
3079 invalidateRect(dirtyRect);
3082 IntRect FrameView::windowResizerRect() const
3084 if (Page* page = frame().page())
3085 return page->chrome().windowResizerRect();
3089 float FrameView::visibleContentScaleFactor() const
3091 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3094 return frame().page()->pageScaleFactor();
3097 void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3099 if (!frame().isMainFrame())
3102 frame().page()->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3105 ScrollableArea* FrameView::enclosingScrollableArea() const
3107 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3111 IntRect FrameView::scrollableAreaBoundingBox() const
3113 RenderWidget* ownerRenderer = frame().ownerRenderer();
3117 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3120 bool FrameView::isScrollable()
3123 // 1) If there an actual overflow.
3124 // 2) display:none or visibility:hidden set to self or inherited.
3125 // 3) overflow{-x,-y}: hidden;
3126 // 4) scrolling: no;
3129 IntSize totalContentsSize = this->totalContentsSize();
3130 IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size();
3131 if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width()))
3135 HTMLFrameOwnerElement* owner = frame().ownerElement();
3136 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3140 ScrollbarMode horizontalMode;
3141 ScrollbarMode verticalMode;
3142 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3143 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3149 void FrameView::updateScrollableAreaSet()
3151 // That ensures that only inner frames are cached.
3152 FrameView* parentFrameView = this->parentFrameView();
3153 if (!parentFrameView)
3156 if (!isScrollable()) {
3157 parentFrameView->removeScrollableArea(this);
3161 parentFrameView->addScrollableArea(this);
3164 bool FrameView::shouldSuspendScrollAnimations() const
3166 return frame().loader().state() != FrameStateComplete;
3169 void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate)
3171 if (!frame().isMainFrame())
3174 frame().page()->chrome().client().recommendedScrollbarStyleDidChange(newStyle);
3177 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
3180 void FrameView::notifyPageThatContentAreaWillPaint() const
3182 Page* page = frame().page();
3186 contentAreaWillPaint();
3188 if (!m_scrollableAreas)
3191 for (auto& scrollableArea : *m_scrollableAreas)
3192 scrollableArea->contentAreaWillPaint();
3195 bool FrameView::scrollAnimatorEnabled() const
3197 #if ENABLE(SMOOTH_SCROLLING)
3198 if (Page* page = frame().page())
3199 return page->settings().scrollAnimatorEnabled();
3205 #if ENABLE(DASHBOARD_SUPPORT)
3206 void FrameView::updateAnnotatedRegions()
3208 Document* document = frame().document();
3209 if (!document->hasAnnotatedRegions())
3211 Vector<AnnotatedRegionValue> newRegions;
3212 document->renderBox()->collectAnnotatedRegions(newRegions);
3213 if (newRegions == document->annotatedRegions())
3215 document->setAnnotatedRegions(newRegions);
3216 Page* page = frame().page();
3219 page->chrome().client().annotatedRegionsChanged();
3223 void FrameView::updateScrollCorner()
3225 RenderElement* renderer = 0;
3226 RefPtr<RenderStyle> cornerStyle;
3227 IntRect cornerRect = scrollCornerRect();
3229 if (!cornerRect.isEmpty()) {
3230 // Try the <body> element first as a scroll corner source.
3231 Document* doc = frame().document();
3232 Element* body = doc ? doc->body() : 0;
3233 if (body && body->renderer()) {
3234 renderer = body->renderer();
3235 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3239 // If the <body> didn't have a custom style, then the root element might.
3240 Element* docElement = doc ? doc->documentElement() : 0;
3241 if (docElement && docElement->renderer()) {
3242 renderer = docElement->renderer();
3243 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3248 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
3249 if (RenderWidget* renderer = frame().ownerRenderer())
3250 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3255 m_scrollCorner = nullptr;
3257 if (!m_scrollCorner) {
3258 m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer->document(), cornerStyle.releaseNonNull());
3259 m_scrollCorner->initializeStyle();
3261 m_scrollCorner->setStyle(cornerStyle.releaseNonNull());
3262 invalidateScrollCorner(cornerRect);
3265 ScrollView::updateScrollCorner();
3268 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
3270 if (context->updatingControlTints()) {
3271 updateScrollCorner();
3275 if (m_scrollCorner) {
3276 if (frame().isMainFrame())
3277 context->fillRect(cornerRect, baseBackgroundColor(), ColorSpaceDeviceRGB);
3278 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
3282 ScrollView::paintScrollCorner(context, cornerRect);
3285 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
3287 if (bar->isCustomScrollbar() && frame().isMainFrame()) {
3288 IntRect toFill = bar->frameRect();
3289 toFill.intersect(rect);
3290 context->fillRect(toFill, baseBackgroundColor(), ColorSpaceDeviceRGB);
3293 ScrollView::paintScrollbar(context, bar, rect);
3296 Color FrameView::documentBackgroundColor() const
3298 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
3299 // the document and the body against the base background color of the frame view.
3300 // Background images are unfortunately impractical to include.
3302 // Return invalid Color objects whenever there is insufficient information.
3303 if (!frame().document())
3306 Element* htmlElement = frame().document()->documentElement();
3307 Element* bodyElement = frame().document()->body();
3309 // Start with invalid colors.
3310 Color htmlBackgroundColor;
3311 Color bodyBackgroundColor;
3312 if (htmlElement && htmlElement->renderer())
3313 htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3314 if (bodyElement && bodyElement->renderer())
3315 bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3317 if (!bodyBackgroundColor.isValid()) {
3318 if (!htmlBackgroundColor.isValid())
3320 return baseBackgroundColor().blend(htmlBackgroundColor);
3323 if (!htmlBackgroundColor.isValid())
3324 return baseBackgroundColor().blend(bodyBackgroundColor);
3326 // We take the aggregate of the base background color
3327 // the <html> background color, and the <body>
3328 // background color to find the document color. The
3329 // addition of the base background color is not
3330 // technically part of the document background, but it
3331 // otherwise poses problems when the aggregate is not
3333 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor);
3336 bool FrameView::hasCustomScrollbars() const
3338 for (auto& widget : children()) {
3339 if (widget->isFrameView()) {
3340 if (toFrameView(*widget).hasCustomScrollbars())
3342 } else if (widget->isScrollbar()) {
3343 if (toScrollbar(*widget).isCustomScrollbar())
3351 FrameView* FrameView::parentFrameView() const
3356 if (Frame* parentFrame = frame().tree().parent())
3357 return parentFrame->view();
3362 bool FrameView::isInChildFrameWithFrameFlattening() const
3364 if (!parent() || !frame().ownerElement())
3367 // Frame flattening applies when the owner element is either in a frameset or
3368 // an iframe with flattening parameters.
3369 if (frame().ownerElement()->hasTagName(iframeTag)) {
3370 RenderIFrame* iframeRenderer = toRenderIFrame(frame().ownerElement()->renderWidget());
3371 if (iframeRenderer->flattenFrame())
3375 if (!frameFlatteningEnabled())
3378 if (frame().ownerElement()->hasTagName(frameTag))
3384 void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree)
3386 // When we start a layout at the child level as opposed to the topmost frame view and this child
3387 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
3388 // will hit this view eventually.
3389 FrameView* parentView = parentFrameView();
3393 // In the middle of parent layout, no need to restart from topmost.
3394 if (parentView->m_nestedLayoutCount)
3397 // Parent tree is clean. Starting layout from it would have no effect.
3398 if (!parentView->needsLayout())
3401 while (parentView->parentFrameView())
3402 parentView = parentView->parentFrameView();
3404 parentView->layout(allowSubtree);
3406 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
3407 ASSERT_UNUSED(root, !root->needsLayout());
3410 void FrameView::updateControlTints()
3412 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
3413 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
3414 // This is only done if the theme supports control tinting. It's up to the theme and platform
3415 // to define when controls get the tint and to call this function when that changes.
3417 // Optimize the common case where we bring a window to the front while it's still empty.
3418 if (frame().document()->url().isEmpty())
3421 RenderView* renderView = this->renderView();
3422 if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars())
3423 paintControlTints();
3426 void FrameView::paintControlTints()
3430 PlatformGraphicsContext* const noContext = 0;
3431 GraphicsContext context(noContext);
3432 context.setUpdatingControlTints(true);
3433 if (platformWidget()) {
3434 // FIXME: consult paintsEntireContents().
3435 paintContents(&context, visibleContentRect(LegacyIOSDocumentVisibleRect));
3437 paint(&context, frameRect());
3440 bool FrameView::wasScrolledByUser() const
3442 return m_wasScrolledByUser;
3445 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
3447 if (m_inProgrammaticScroll)
3449 m_maintainScrollPositionAnchor = 0;
3450 if (m_wasScrolledByUser == wasScrolledByUser)
3452 m_wasScrolledByUser = wasScrolledByUser;
3453 adjustTiledBackingCoverage();
3456 void FrameView::willPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3458 Document* document = frame().document();
3460 if (!context->paintingDisabled())
3461 InspectorInstrumentation::willPaint(renderView());
3463 paintingState.isTopLevelPainter = !sCurrentPaintTimeStamp;
3465 if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure()) {
3466 LOG(MemoryPressure, "Under memory pressure: %s", WTF_PRETTY_FUNCTION);
3468 // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since
3469 // we might need some live bitmaps on painting.
3470 memoryCache()->prune();
3473 if (paintingState.isTopLevelPainter)
3474 sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
3476 paintingState.paintBehavior = m_paintBehavior;
3478 if (FrameView* parentView = parentFrameView()) {
3479 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
3480 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3483 if (m_paintBehavior == PaintBehaviorNormal)
3484 document->markers().invalidateRenderedRectsForMarkersInRect(dirtyRect);
3486 if (document->printing())
3487 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3489 paintingState.isFlatteningPaintOfRootFrame = (m_paintBehavior & PaintBehaviorFlattenCompositingLayers) && !frame().ownerElement();
3490 if (paintingState.isFlatteningPaintOfRootFrame)
3491 notifyWidgetsInAllFrames(WillPaintFlattened);
3493 ASSERT(!m_isPainting);
3494 m_isPainting = true;
3497 void FrameView::didPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3499 m_isPainting = false;
3501 if (paintingState.isFlatteningPaintOfRootFrame)
3502 notifyWidgetsInAllFrames(DidPaintFlattened);
3504 m_paintBehavior = paintingState.paintBehavior;
3505 m_lastPaintTime = monotonicallyIncreasingTime();
3507 // Painting can lead to decoding of large amounts of bitmaps
3508 // If we are low on memory, wipe them out after the paint.
3509 if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure())
3510 memoryCache()->pruneLiveResources(true);
3512 // Regions may have changed as a result of the visibility/z-index of element changing.
3513 #if ENABLE(DASHBOARD_SUPPORT)
3514 if (frame().document()->annotatedRegionsDirty())
3515 updateAnnotatedRegions();
3518 if (paintingState.isTopLevelPainter)
3519 sCurrentPaintTimeStamp = 0;
3521 if (!context->paintingDisabled()) {
3522 InspectorInstrumentation::didPaint(renderView(), context, dirtyRect);
3523 // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623
3524 firePaintRelatedMilestonesIfNeeded();
3528 void FrameView::paintContents(GraphicsContext* context, const IntRect& dirtyRect)
3532 if (frame().document()->printing())
3533 fillWithRed = false; // Printing, don't fill with red (can't remember why).
3534 else if (frame().ownerElement())
3535 fillWithRed = false; // Subframe, don't fill with red.
3536 else if (isTransparent())
3537 fillWithRed = false; // Transparent, don't fill with red.
3538 else if (m_paintBehavior & PaintBehaviorSelectionOnly)
3539 fillWithRed = false; // Selections are transparent, don't fill with red.
3540 else if (m_nodeToDraw)
3541 fillWithRed = false; // Element images are transparent, don't fill with red.
3546 context->fillRect(dirtyRect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
3549 RenderView* renderView = this->renderView();
3551 LOG_ERROR("called FrameView::paint with nil renderer");
3555 ASSERT(!needsLayout());
3559 PaintingState paintingState;
3560 willPaintContents(context, dirtyRect, paintingState);
3562 FontCachePurgePreventer fontCachePurgePreventer;
3564 // m_nodeToDraw is used to draw only one element (and its descendants)
3565 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
3566 RenderLayer* rootLayer = renderView->layer();
3569 RenderElement::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(&rootLayer->renderer());
3572 rootLayer->paint(context, dirtyRect, m_paintBehavior, eltRenderer);
3573 if (rootLayer->containsDirtyOverlayScrollbars())
3574 rootLayer->paintOverlayScrollbars(context, dirtyRect, m_paintBehavior, eltRenderer);
3576 didPaintContents(context, dirtyRect, paintingState);
3579 void FrameView::setPaintBehavior(PaintBehavior behavior)
3581 m_paintBehavior = behavior;
3584 PaintBehavior FrameView::paintBehavior() const
3586 return m_paintBehavior;
3589 bool FrameView::isPainting() const
3591 return m_isPainting;
3594 // FIXME: change this to use the subtreePaint terminology.
3595 void FrameView::setNodeToDraw(Node* node)
3597 m_nodeToDraw = node;
3600 void FrameView::paintContentsForSnapshot(GraphicsContext* context, const IntRect& imageRect, SelectionInSnapshot shouldPaintSelection, CoordinateSpaceForSnapshot coordinateSpace)
3602 updateLayoutAndStyleIfNeededRecursive();
3604 // Cache paint behavior and set a new behavior appropriate for snapshots.
3605 PaintBehavior oldBehavior = paintBehavior();
3606 setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
3608 // If the snapshot should exclude selection, then we'll clear the current selection
3609 // in the render tree only. This will allow us to restore the selection from the DOM
3610 // after we paint the snapshot.
3611 if (shouldPaintSelection == ExcludeSelection) {
3612 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
3613 if (RenderView* root = frame->contentRenderer())
3614 root->clearSelection();