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"
109 using namespace HTMLNames;
111 double FrameView::sCurrentPaintTimeStamp = 0.0;
113 // The maximum number of updateEmbeddedObjects iterations that should be done before returning.
114 static const unsigned maxUpdateEmbeddedObjectsIterations = 2;
116 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
118 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
119 if (didFullRepaint) {
120 flags &= ~RenderLayer::CheckForRepaint;
121 flags |= RenderLayer::NeedsFullRepaintInBacking;
123 if (isRelayoutingSubtree && layer->enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers))
124 flags |= RenderLayer::UpdatePagination;
128 Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style)
130 EOverflow overflow = style.overflowY();
131 if (overflow != OPAGEDX && overflow != OPAGEDY)
132 return Pagination::Unpaginated;
134 bool isHorizontalWritingMode = style.isHorizontalWritingMode();
135 TextDirection textDirection = style.direction();
136 WritingMode writingMode = style.writingMode();
138 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode
139 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode
140 // is vertical, then the direction of the verticality dictates the choice.
141 if (overflow == OPAGEDX) {
142 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode)
143 return Pagination::LeftToRightPaginated;
144 return Pagination::RightToLeftPaginated;
147 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode
148 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode
149 // is vertical, then we use TextDirection to choose between those options.
150 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL))
151 return Pagination::TopToBottomPaginated;
152 return Pagination::BottomToTopPaginated;
155 FrameView::FrameView(Frame& frame)
157 , m_canHaveScrollbars(true)
158 , m_layoutTimer(this, &FrameView::layoutTimerFired)
160 , m_layoutPhase(OutsideLayout)
161 , m_inSynchronousPostLayout(false)
162 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
163 , m_updateEmbeddedObjectsTimer(this, &FrameView::updateEmbeddedObjectsTimerFired)
164 , m_isTransparent(false)
165 , m_baseBackgroundColor(Color::white)
166 , m_mediaType("screen")
167 , m_overflowStatusDirty(true)
168 , m_viewportRenderer(0)
169 , m_wasScrolledByUser(false)
170 , m_inProgrammaticScroll(false)
171 , m_safeToPropagateScrollToParent(true)
172 , m_isTrackingRepaints(false)
173 , m_shouldUpdateWhileOffscreen(true)
174 , m_exposedRect(FloatRect::infiniteRect())
175 , m_deferSetNeedsLayouts(0)
176 , m_setNeedsLayoutWasDeferred(false)
177 , m_speculativeTilingEnabled(false)
178 , m_speculativeTilingEnableTimer(this, &FrameView::speculativeTilingEnableTimerFired)
180 , m_useCustomFixedPositionLayoutRect(false)
181 , m_useCustomSizeForResizeEvent(false)
183 , m_hasOverrideViewportSize(false)
184 , m_shouldAutoSize(false)
185 , m_inAutoSize(false)
186 , m_didRunAutosize(false)
187 , m_autoSizeFixedMinimumHeight(0)
190 , m_milestonesPendingPaint(0)
191 , m_visualUpdatesAllowedByClient(true)
192 , m_scrollPinningBehavior(DoNotPin)
196 if (frame.isMainFrame()) {
197 ScrollableArea::setVerticalScrollElasticity(m_frame->page() ? m_frame->page()->verticalScrollElasticity() : ScrollElasticityAllowed);
198 ScrollableArea::setHorizontalScrollElasticity(m_frame->page() ? m_frame->page()->horizontalScrollElasticity() : ScrollElasticityAllowed);
202 PassRefPtr<FrameView> FrameView::create(Frame& frame)
204 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
206 return view.release();
209 PassRefPtr<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
211 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
212 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
214 return view.release();
217 FrameView::~FrameView()
219 if (m_postLayoutTasksTimer.isActive())
220 m_postLayoutTasksTimer.stop();
222 removeFromAXObjectCache();
225 // Custom scrollbars should already be destroyed at this point
226 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
227 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
229 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
230 setHasVerticalScrollbar(false);
232 ASSERT(!m_scrollCorner);
234 ASSERT(frame().view() != this || !frame().contentRenderer());
237 void FrameView::reset()
239 m_cannotBlitToWindow = false;
240 m_isOverlapped = false;
241 m_contentIsOpaque = false;
242 m_layoutTimer.stop();
244 m_delayedLayout = false;
245 m_needsFullRepaint = true;
246 m_layoutSchedulingEnabled = true;
247 m_layoutPhase = OutsideLayout;
248 m_inSynchronousPostLayout = false;
250 m_nestedLayoutCount = 0;
251 m_postLayoutTasksTimer.stop();
252 m_updateEmbeddedObjectsTimer.stop();
253 m_firstLayout = true;
254 m_firstLayoutCallbackPending = false;
255 m_wasScrolledByUser = false;
256 m_safeToPropagateScrollToParent = true;
257 m_lastViewportSize = IntSize();
258 m_lastZoomFactor = 1.0f;
259 m_isTrackingRepaints = false;
260 m_trackedRepaintRects.clear();
262 m_paintBehavior = PaintBehaviorNormal;
263 m_isPainting = false;
264 m_visuallyNonEmptyCharacterCount = 0;
265 m_visuallyNonEmptyPixelCount = 0;
266 m_isVisuallyNonEmpty = false;
267 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
268 m_maintainScrollPositionAnchor = 0;
271 void FrameView::removeFromAXObjectCache()
273 if (AXObjectCache* cache = axObjectCache())
277 void FrameView::resetScrollbars()
279 // Reset the document's scrollbars back to our defaults before we yield the floor.
280 m_firstLayout = true;
281 setScrollbarsSuppressed(true);
282 if (m_canHaveScrollbars)
283 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
285 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
286 setScrollbarsSuppressed(false);
289 void FrameView::resetScrollbarsAndClearContentsSize()
293 setScrollbarsSuppressed(true);
294 setContentsSize(IntSize());
295 setScrollbarsSuppressed(false);
298 void FrameView::init()
302 m_margins = LayoutSize(-1, -1); // undefined
303 m_size = LayoutSize();
305 // Propagate the marginwidth/height and scrolling modes to the view.
306 Element* ownerElement = frame().ownerElement();
307 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
308 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
309 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
310 setCanHaveScrollbars(false);
311 LayoutUnit marginWidth = frameElt->marginWidth();
312 LayoutUnit marginHeight = frameElt->marginHeight();
313 if (marginWidth != -1)
314 setMarginWidth(marginWidth);
315 if (marginHeight != -1)
316 setMarginHeight(marginHeight);
319 Page* page = frame().page();
320 if (page && page->chrome().client().shouldPaintEntireContents())
321 setPaintsEntireContents(true);
324 void FrameView::prepareForDetach()
326 detachCustomScrollbars();
327 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
328 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
329 removeFromAXObjectCache();
331 if (frame().page()) {
332 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
333 scrollingCoordinator->willDestroyScrollableArea(this);
337 void FrameView::detachCustomScrollbars()
339 Scrollbar* horizontalBar = horizontalScrollbar();
340 if (horizontalBar && horizontalBar->isCustomScrollbar())
341 setHasHorizontalScrollbar(false);
343 Scrollbar* verticalBar = verticalScrollbar();
344 if (verticalBar && verticalBar->isCustomScrollbar())
345 setHasVerticalScrollbar(false);
347 m_scrollCorner = nullptr;
350 void FrameView::recalculateScrollbarOverlayStyle()
352 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
353 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
355 Color backgroundColor = documentBackgroundColor();
356 if (backgroundColor.isValid()) {
357 // Reduce the background color from RGB to a lightness value
358 // and determine which scrollbar style to use based on a lightness
360 double hue, saturation, lightness;
361 backgroundColor.getHSL(hue, saturation, lightness);
362 if (lightness <= .5 && backgroundColor.alpha() > 0)
363 overlayStyle = ScrollbarOverlayStyleLight;
366 if (oldOverlayStyle != overlayStyle)
367 setScrollbarOverlayStyle(overlayStyle);
370 void FrameView::clear()
372 setCanBlitOnScroll(true);
376 setScrollbarsSuppressed(true);
379 // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
380 // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
381 if (LegacyTileCache* tileCache = legacyTileCache())
382 tileCache->setTilingMode(LegacyTileCache::Disabled);
386 bool FrameView::didFirstLayout() const
388 return !m_firstLayout;
391 void FrameView::invalidateRect(const IntRect& rect)
394 if (HostWindow* window = hostWindow())
395 window->invalidateContentsAndRootView(rect);
399 RenderWidget* renderer = frame().ownerRenderer();
403 IntRect repaintRect = rect;
404 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
405 renderer->borderTop() + renderer->paddingTop());
406 renderer->repaintRectangle(repaintRect);
409 void FrameView::setFrameRect(const IntRect& newRect)
411 IntRect oldRect = frameRect();
412 if (newRect == oldRect)
415 #if ENABLE(TEXT_AUTOSIZING)
416 // Autosized font sizes depend on the width of the viewing area.
417 if (newRect.width() != oldRect.width()) {
418 Page* page = frame().page();
419 if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) {
420 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
421 frame().document()->textAutosizer()->recalculateMultipliers();
426 ScrollView::setFrameRect(newRect);
428 updateScrollableAreaSet();
430 if (RenderView* renderView = this->renderView()) {
431 if (renderView->usesCompositing())
432 renderView->compositor().frameViewDidChangeSize();
436 #if ENABLE(REQUEST_ANIMATION_FRAME)
437 bool FrameView::scheduleAnimation()
439 if (HostWindow* window = hostWindow()) {
440 window->scheduleAnimation();
447 void FrameView::setMarginWidth(LayoutUnit w)
449 // make it update the rendering area when set
450 m_margins.setWidth(w);
453 void FrameView::setMarginHeight(LayoutUnit h)
455 // make it update the rendering area when set
456 m_margins.setHeight(h);
459 bool FrameView::frameFlatteningEnabled() const
461 return frame().settings().frameFlatteningEnabled();
464 bool FrameView::isFrameFlatteningValidForThisFrame() const
466 if (!frameFlatteningEnabled())
469 HTMLFrameOwnerElement* owner = frame().ownerElement();
473 // Frame flattening is valid only for <frame> and <iframe>.
474 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
477 bool FrameView::avoidScrollbarCreation() const
479 // with frame flattening no subframe can have scrollbars
480 // but we also cannot turn scrollbars off as we determine
481 // our flattening policy using that.
482 return isFrameFlatteningValidForThisFrame();
485 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
487 m_canHaveScrollbars = canHaveScrollbars;
488 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
491 void FrameView::updateCanHaveScrollbars()
495 scrollbarModes(hMode, vMode);
496 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
497 setCanHaveScrollbars(false);
499 setCanHaveScrollbars(true);
502 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
504 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
505 return ScrollView::createScrollbar(orientation);
507 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
508 Document* doc = frame().document();
510 // Try the <body> element first as a scrollbar source.
511 Element* body = doc ? doc->body() : 0;
512 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
513 return RenderScrollbar::createCustomScrollbar(this, orientation, body);
515 // If the <body> didn't have a custom style, then the root element might.
516 Element* docElement = doc ? doc->documentElement() : 0;
517 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
518 return RenderScrollbar::createCustomScrollbar(this, orientation, docElement);
520 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
521 RenderWidget* frameRenderer = frame().ownerRenderer();
522 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
523 return RenderScrollbar::createCustomScrollbar(this, orientation, 0, &frame());
525 // Nobody set a custom style, so we just use a native scrollbar.
526 return ScrollView::createScrollbar(orientation);
529 void FrameView::setContentsSize(const IntSize& size)
531 if (size == contentsSize())
534 m_deferSetNeedsLayouts++;
536 ScrollView::setContentsSize(size);
537 ScrollView::contentsResized();
539 Page* page = frame().page();
543 updateScrollableAreaSet();
545 page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
547 ASSERT(m_deferSetNeedsLayouts);
548 m_deferSetNeedsLayouts--;
550 if (!m_deferSetNeedsLayouts)
551 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
554 void FrameView::adjustViewSize()
556 RenderView* renderView = this->renderView();
560 ASSERT(frame().view() == this);
562 const IntRect rect = renderView->documentRect();
563 const IntSize& size = rect.size();
564 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
566 setContentsSize(size);
569 void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
571 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
572 // overflow:hidden and overflow:scroll on <body> as applying to the document's
573 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
574 // use the root element.
576 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
577 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
580 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
582 EOverflow overflowX = o->style().overflowX();
583 EOverflow overflowY = o->style().overflowY();
585 if (o->isSVGRoot()) {
586 // FIXME: evaluate if we can allow overflow for these cases too.
587 // Overflow is always hidden when stand-alone SVG documents are embedded.
588 if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
597 hMode = ScrollbarAuto;
599 hMode = ScrollbarAlwaysOff;
602 hMode = ScrollbarAlwaysOn;
605 hMode = ScrollbarAuto;
608 // Don't set it at all.
615 vMode = ScrollbarAuto;
617 vMode = ScrollbarAlwaysOff;
620 vMode = ScrollbarAlwaysOn;
623 vMode = ScrollbarAuto;
626 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
630 m_viewportRenderer = o;
633 void FrameView::applyPaginationToViewport()
635 Document* document = frame().document();
636 auto documentElement = document->documentElement();
637 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
638 RenderElement* documentOrBodyRenderer = documentRenderer;
639 auto body = document->body();
640 if (body && body->renderer()) {
641 if (body->hasTagName(bodyTag))
642 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer;
645 Pagination pagination;
647 if (!documentOrBodyRenderer) {
648 setPagination(pagination);
652 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
653 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
654 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
655 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
658 setPagination(pagination);
661 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
663 m_viewportRenderer = 0;
665 const HTMLFrameOwnerElement* owner = frame().ownerElement();
666 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
667 hMode = ScrollbarAlwaysOff;
668 vMode = ScrollbarAlwaysOff;
672 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
673 hMode = ScrollbarAuto;
674 vMode = ScrollbarAuto;
676 hMode = ScrollbarAlwaysOff;
677 vMode = ScrollbarAlwaysOff;
681 Document* document = frame().document();
682 auto documentElement = document->documentElement();
683 RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr;
684 auto body = document->body();
685 if (body && body->renderer()) {
686 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
687 vMode = ScrollbarAlwaysOff;
688 hMode = ScrollbarAlwaysOff;
689 } else if (body->hasTagName(bodyTag)) {
690 // It's sufficient to just check the X overflow,
691 // since it's illegal to have visible in only one direction.
692 RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
693 applyOverflowToViewport(o, hMode, vMode);
695 } else if (rootRenderer)
696 applyOverflowToViewport(rootRenderer, hMode, vMode);
700 void FrameView::updateCompositingLayersAfterStyleChange()
702 RenderView* renderView = this->renderView();
706 // If we expect to update compositing after an incipient layout, don't do so here.
707 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
710 RenderLayerCompositor& compositor = renderView->compositor();
711 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
712 compositor.cacheAcceleratedCompositingFlags();
713 compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange);
716 void FrameView::updateCompositingLayersAfterLayout()
718 RenderView* renderView = this->renderView();
722 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
723 renderView->compositor().cacheAcceleratedCompositingFlags();
724 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
727 void FrameView::clearBackingStores()
729 RenderView* renderView = this->renderView();
733 RenderLayerCompositor& compositor = renderView->compositor();
734 ASSERT(compositor.inCompositingMode());
735 compositor.enableCompositingMode(false);
736 compositor.clearBackingForAllLayers();
739 void FrameView::restoreBackingStores()
741 RenderView* renderView = this->renderView();
745 RenderLayerCompositor& compositor = renderView->compositor();
746 compositor.enableCompositingMode(true);
747 compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
750 GraphicsLayer* FrameView::layerForScrolling() const
752 RenderView* renderView = this->renderView();
755 return renderView->compositor().scrollLayer();
758 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
760 RenderView* renderView = this->renderView();
763 return renderView->compositor().layerForHorizontalScrollbar();
766 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
768 RenderView* renderView = this->renderView();
771 return renderView->compositor().layerForVerticalScrollbar();
774 GraphicsLayer* FrameView::layerForScrollCorner() const
776 RenderView* renderView = this->renderView();
779 return renderView->compositor().layerForScrollCorner();
782 TiledBacking* FrameView::tiledBacking() const
784 RenderView* renderView = this->renderView();
788 RenderLayerBacking* backing = renderView->layer()->backing();
792 return backing->graphicsLayer()->tiledBacking();
795 uint64_t FrameView::scrollLayerID() const
797 RenderView* renderView = this->renderView();
801 RenderLayerBacking* backing = renderView->layer()->backing();
805 return backing->scrollingNodeIDForRole(FrameScrollingNode);
808 ScrollableArea* FrameView::scrollableAreaForScrollLayerID(uint64_t nodeID) const
810 RenderView* renderView = this->renderView();
814 return renderView->compositor().scrollableAreaForScrollLayerID(nodeID);
817 #if ENABLE(RUBBER_BANDING)
818 GraphicsLayer* FrameView::layerForOverhangAreas() const
820 RenderView* renderView = this->renderView();
823 return renderView->compositor().layerForOverhangAreas();
826 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
828 RenderView* renderView = this->renderView();
832 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
835 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
837 RenderView* renderView = this->renderView();
841 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
844 #endif // ENABLE(RUBBER_BANDING)
846 bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush)
848 RenderView* renderView = this->renderView();
850 return true; // We don't want to keep trying to update layers if we have no renderer.
852 ASSERT(frame().view() == this);
854 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
855 // layer content to occur before layout has happened, which will cause paintContents() to bail.
860 if (LegacyTileCache* tileCache = legacyTileCache())
861 tileCache->doPendingRepaints();
864 renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame());
869 void FrameView::setNeedsOneShotDrawingSynchronization()
871 if (Page* page = frame().page())
872 page->chrome().client().setNeedsOneShotDrawingSynchronization();
875 GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
877 // To find the Widget that corresponds with platformWidget we have to do a linear
878 // search of our child widgets.
879 Widget* foundWidget = nullptr;
880 for (auto& widget : children()) {
881 if (widget->platformWidget() != platformWidget)
883 foundWidget = widget.get();
890 auto* renderWidget = RenderWidget::find(foundWidget);
894 RenderLayer* widgetLayer = renderWidget->layer();
895 if (!widgetLayer || !widgetLayer->isComposited())
898 return widgetLayer->backing()->parentForSublayers();
901 void FrameView::scheduleLayerFlushAllowingThrottling()
903 RenderView* view = this->renderView();
906 view->compositor().scheduleLayerFlush(true /* canThrottle */);
909 void FrameView::setHeaderHeight(int headerHeight)
912 ASSERT(frame().isMainFrame());
913 m_headerHeight = headerHeight;
915 if (RenderView* renderView = this->renderView())
916 renderView->setNeedsLayout();
919 void FrameView::setFooterHeight(int footerHeight)
922 ASSERT(frame().isMainFrame());
923 m_footerHeight = footerHeight;
925 if (RenderView* renderView = this->renderView())
926 renderView->setNeedsLayout();
929 float FrameView::topContentInset() const
931 if (!frame().isMainFrame())
934 Page* page = frame().page();
935 return page ? page->topContentInset() : 0;
938 void FrameView::topContentInsetDidChange()
940 RenderView* renderView = this->renderView();
946 updateScrollbars(scrollOffset());
947 if (renderView->usesCompositing())
948 renderView->compositor().frameViewDidChangeSize();
950 if (TiledBacking* tiledBacking = this->tiledBacking())
951 tiledBacking->setTopContentInset(topContentInset());
954 bool FrameView::hasCompositedContent() const
956 if (RenderView* renderView = this->renderView())
957 return renderView->compositor().inCompositingMode();
961 bool FrameView::hasCompositedContentIncludingDescendants() const
963 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
964 RenderView* renderView = frame->contentRenderer();
965 if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : 0) {
966 if (compositor->inCompositingMode())
969 if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this))
976 bool FrameView::hasCompositingAncestor() const
978 for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) {
979 if (FrameView* view = frame->view()) {
980 if (view->hasCompositedContent())
987 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
988 void FrameView::enterCompositingMode()
990 if (RenderView* renderView = this->renderView()) {
991 renderView->compositor().enableCompositingMode();
993 renderView->compositor().scheduleCompositingLayerUpdate();
997 bool FrameView::isEnclosedInCompositingLayer() const
999 auto frameOwnerRenderer = frame().ownerRenderer();
1000 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
1003 if (FrameView* parentView = parentFrameView())
1004 return parentView->isEnclosedInCompositingLayer();
1008 bool FrameView::flushCompositingStateIncludingSubframes()
1010 bool allFramesFlushed = flushCompositingStateForThisFrame(&frame());
1012 for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) {
1013 bool flushed = child->view()->flushCompositingStateForThisFrame(&frame());
1014 allFramesFlushed &= flushed;
1016 return allFramesFlushed;
1019 bool FrameView::isSoftwareRenderable() const
1021 RenderView* renderView = this->renderView();
1022 return !renderView || !renderView->compositor().has3DContent();
1025 void FrameView::didMoveOnscreen()
1027 contentAreaDidShow();
1030 void FrameView::willMoveOffscreen()
1032 contentAreaDidHide();
1035 void FrameView::setIsInWindow(bool isInWindow)
1037 if (RenderView* renderView = this->renderView())
1038 renderView->setIsInWindow(isInWindow);
1041 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
1043 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
1046 inline void FrameView::forceLayoutParentViewIfNeeded()
1048 RenderWidget* ownerRenderer = frame().ownerRenderer();
1052 RenderBox* contentBox = embeddedContentBox();
1056 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
1057 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
1060 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1061 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1062 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
1063 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1064 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1065 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1066 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1067 Ref<FrameView> frameView(ownerRenderer->view().frameView());
1069 // Mark the owner renderer as needing layout.
1070 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1072 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
1073 frameView->layout();
1076 void FrameView::layout(bool allowSubtree)
1081 // Protect the view from being deleted during layout (in recalcStyle).
1082 Ref<FrameView> protect(*this);
1084 // Many of the tasks performed during layout can cause this function to be re-entered,
1085 // so save the layout phase now and restore it on exit.
1086 TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1088 // Every scroll that happens during layout is programmatic.
1089 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1091 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1093 if (inChildFrameLayoutWithFrameFlattening) {
1094 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1095 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1096 if (!root || !root->needsLayout())
1101 if (updateFixedPositionLayoutRect())
1102 allowSubtree = false;
1105 m_layoutTimer.stop();
1106 m_delayedLayout = false;
1107 m_setNeedsLayoutWasDeferred = false;
1109 // we shouldn't enter layout() while painting
1110 ASSERT(!isPainting());
1114 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(&frame());
1116 if (!allowSubtree && m_layoutRoot) {
1117 m_layoutRoot->markContainingBlocksForLayout(false);
1121 ASSERT(frame().view() == this);
1122 ASSERT(frame().document());
1124 Document& document = *frame().document();
1125 ASSERT(!document.inPageCache());
1128 RenderElement* root;
1131 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1133 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1134 // This is a new top-level layout. If there are any remaining tasks from the previous
1135 // layout, finish them now.
1136 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1137 performPostLayoutTasks();
1140 m_layoutPhase = InPreLayoutStyleUpdate;
1142 // Viewport-dependent media queries may cause us to need completely different style information.
1143 StyleResolver* styleResolver = document.styleResolverIfExists();
1144 if (!styleResolver || styleResolver->hasMediaQueriesAffectedByViewportChange()) {
1145 document.styleResolverChanged(DeferRecalcStyle);
1146 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1147 InspectorInstrumentation::mediaQueryResultChanged(&document);
1149 document.evaluateMediaQueryList();
1151 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1152 // take care of that now.
1153 applyPaginationToViewport();
1155 // Always ensure our style info is up-to-date. This can happen in situations where
1156 // the layout beats any sort of style recalc update that needs to occur.
1157 document.updateStyleIfNeeded();
1158 m_layoutPhase = InPreLayout;
1160 subtree = m_layoutRoot;
1162 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1163 // so there's no point to continuing to layout
1167 root = subtree ? m_layoutRoot : document.renderView();
1169 // FIXME: Do we need to set m_size here?
1173 // Close block here so we can set up the font cache purge preventer, which we will still
1174 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1175 // The next block sets m_layoutSchedulingEnabled back to false once again.
1178 FontCachePurgePreventer fontCachePurgePreventer;
1181 ++m_nestedLayoutCount;
1184 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1186 if (!m_layoutRoot) {
1187 HTMLElement* body = document.body();
1188 if (body && body->renderer()) {
1189 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
1190 body->renderer()->setChildNeedsLayout();
1191 } else if (body->hasTagName(bodyTag)) {
1192 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox().stretchesToViewport())
1193 body->renderer()->setChildNeedsLayout();
1197 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1198 if (m_firstLayout && !frame().ownerElement())
1199 printf("Elapsed time before first layout: %lld\n", document.elapsedTime().count());
1203 autoSizeIfEnabled();
1205 m_needsFullRepaint = !subtree && (m_firstLayout || toRenderView(*root).printing());
1208 ScrollbarMode hMode;
1209 ScrollbarMode vMode;
1210 calculateScrollbarModesForLayout(hMode, vMode);
1212 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1213 if (m_firstLayout) {
1214 setScrollbarsSuppressed(true);
1216 m_firstLayout = false;
1217 m_firstLayoutCallbackPending = true;
1218 m_lastViewportSize = sizeForResizeEvent();
1219 m_lastZoomFactor = root->style().zoom();
1221 // Set the initial vMode to AlwaysOn if we're auto.
1222 if (vMode == ScrollbarAuto)
1223 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1224 // Set the initial hMode to AlwaysOff if we're auto.
1225 if (hMode == ScrollbarAuto)
1226 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1228 setScrollbarModes(hMode, vMode);
1229 setScrollbarsSuppressed(false, true);
1231 setScrollbarModes(hMode, vMode);
1234 LayoutSize oldSize = m_size;
1236 m_size = layoutSize();
1238 if (oldSize != m_size) {
1239 m_needsFullRepaint = true;
1240 if (!m_firstLayout) {
1241 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : 0;
1242 RenderBox* bodyRenderer = rootRenderer && document.body() ? document.body()->renderBox() : 0;
1243 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1244 bodyRenderer->setChildNeedsLayout();
1245 else if (rootRenderer && rootRenderer->stretchesToViewport())
1246 rootRenderer->setChildNeedsLayout();
1248 document.updateViewportUnitsOnResize();
1252 m_layoutPhase = InPreLayout;
1255 layer = root->enclosingLayer();
1257 bool disableLayoutState = false;
1259 disableLayoutState = root->view().shouldDisableLayoutStateForSubtree(root);
1260 root->view().pushLayoutState(*root);
1262 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? &root->view() : 0);
1263 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(&root->view());
1265 ASSERT(m_layoutPhase == InPreLayout);
1266 m_layoutPhase = InLayout;
1268 forceLayoutParentViewIfNeeded();
1270 ASSERT(m_layoutPhase == InLayout);
1273 #if ENABLE(IOS_TEXT_AUTOSIZING)
1274 float minZoomFontSize = frame().settings().minimumZoomFontSize();
1275 float visWidth = frame().page()->textAutosizingWidth();
1276 if (minZoomFontSize && visWidth && !root->view().printing()) {
1277 root->adjustComputedFontSizesOnBlocks(minZoomFontSize, visWidth);
1278 bool needsLayout = root->needsLayout();
1283 #if ENABLE(TEXT_AUTOSIZING)
1284 if (document.textAutosizer()->processSubtree(root) && root->needsLayout())
1288 ASSERT(m_layoutPhase == InLayout);
1291 root->view().popLayoutState(*root);
1295 // Close block here to end the scope of changeSchedulingEnabled and layoutStateDisabler.
1298 m_layoutPhase = InViewSizeAdjust;
1300 bool neededFullRepaint = m_needsFullRepaint;
1302 if (!subtree && !toRenderView(*root).printing())
1305 m_layoutPhase = InPostLayout;
1307 m_needsFullRepaint = neededFullRepaint;
1309 // Now update the positions of all layers.
1310 if (m_needsFullRepaint)
1311 root->view().repaintRootContents();
1313 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1315 updateCompositingLayersAfterLayout();
1319 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1320 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1321 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1324 #if ENABLE(DASHBOARD_SUPPORT)
1325 updateAnnotatedRegions();
1328 #if ENABLE(IOS_TOUCH_EVENTS)
1329 document.dirtyTouchEventRects();
1332 ASSERT(!root->needsLayout());
1334 updateCanBlitOnScrollRecursively();
1336 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1337 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1339 if (!m_postLayoutTasksTimer.isActive()) {
1340 if (!m_inSynchronousPostLayout) {
1341 if (inChildFrameLayoutWithFrameFlattening)
1342 updateWidgetPositions();
1344 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1345 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1349 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1350 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1351 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1352 // can make us need to update again, and we can get stuck in a nasty cycle unless
1353 // we call it through the timer here.
1354 m_postLayoutTasksTimer.startOneShot(0);
1360 InspectorInstrumentation::didLayout(cookie, root);
1362 --m_nestedLayoutCount;
1365 RenderBox* FrameView::embeddedContentBox() const
1367 RenderView* renderView = this->renderView();
1371 RenderObject* firstChild = renderView->firstChild();
1372 if (!firstChild || !firstChild->isBox())
1375 // Curently only embedded SVG documents participate in the size-negotiation logic.
1376 if (toRenderBox(firstChild)->isSVGRoot())
1377 return toRenderBox(firstChild);
1382 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1384 if (!m_embeddedObjectsToUpdate)
1385 m_embeddedObjectsToUpdate = std::make_unique<ListHashSet<RenderEmbeddedObject*>>();
1387 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1388 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
1389 // Tell the DOM element that it needs a widget update.
1390 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
1391 if (!pluginElement.needsCheckForSizeChange())
1392 pluginElement.setNeedsWidgetUpdate(true);
1395 m_embeddedObjectsToUpdate->add(&embeddedObject);
1398 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1400 if (!m_embeddedObjectsToUpdate)
1403 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1406 void FrameView::setMediaType(const String& mediaType)
1408 m_mediaType = mediaType;
1411 String FrameView::mediaType() const
1413 // See if we have an override type.
1414 String overrideType = frame().loader().client().overrideMediaType();
1415 InspectorInstrumentation::applyEmulatedMedia(&frame(), &overrideType);
1416 if (!overrideType.isNull())
1417 return overrideType;
1421 void FrameView::adjustMediaTypeForPrinting(bool printing)
1424 if (m_mediaTypeWhenNotPrinting.isNull())
1425 m_mediaTypeWhenNotPrinting = mediaType();
1426 setMediaType("print");
1428 if (!m_mediaTypeWhenNotPrinting.isNull())
1429 setMediaType(m_mediaTypeWhenNotPrinting);
1430 m_mediaTypeWhenNotPrinting = String();
1434 bool FrameView::useSlowRepaints(bool considerOverlap) const
1436 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1438 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1439 // m_contentIsOpaque, so don't take the fast path for composited layers
1440 // if they are a platform widget in order to get painting correctness
1441 // for transparent layers. See the comment in WidgetMac::paint.
1442 if (contentsInCompositedLayer() && !platformWidget())
1445 bool isOverlapped = m_isOverlapped && considerOverlap;
1447 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1450 if (FrameView* parentView = parentFrameView())
1451 return parentView->useSlowRepaints(considerOverlap);
1456 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1458 return useSlowRepaints(false);
1461 void FrameView::updateCanBlitOnScrollRecursively()
1463 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1464 if (FrameView* view = frame->view())
1465 view->setCanBlitOnScroll(!view->useSlowRepaints());
1469 bool FrameView::contentsInCompositedLayer() const
1471 RenderView* renderView = this->renderView();
1472 if (renderView && renderView->isComposited()) {
1473 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1474 if (layer && layer->drawsContent())
1481 void FrameView::setCannotBlitToWindow()
1483 m_cannotBlitToWindow = true;
1484 updateCanBlitOnScrollRecursively();
1487 void FrameView::addSlowRepaintObject(RenderElement* o)
1489 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1491 if (!m_slowRepaintObjects)
1492 m_slowRepaintObjects = std::make_unique<HashSet<RenderElement*>>();
1494 m_slowRepaintObjects->add(o);
1496 if (!hadSlowRepaintObjects) {
1497 updateCanBlitOnScrollRecursively();
1499 if (Page* page = frame().page()) {
1500 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1501 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1506 void FrameView::removeSlowRepaintObject(RenderElement* o)
1508 if (!m_slowRepaintObjects)
1511 m_slowRepaintObjects->remove(o);
1512 if (m_slowRepaintObjects->isEmpty()) {
1513 m_slowRepaintObjects = nullptr;
1514 updateCanBlitOnScrollRecursively();
1516 if (Page* page = frame().page()) {
1517 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1518 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1523 void FrameView::addViewportConstrainedObject(RenderElement* object)
1525 if (!m_viewportConstrainedObjects)
1526 m_viewportConstrainedObjects = std::make_unique<ViewportConstrainedObjectSet>();
1528 if (!m_viewportConstrainedObjects->contains(object)) {
1529 m_viewportConstrainedObjects->add(object);
1530 if (platformWidget())
1531 updateCanBlitOnScrollRecursively();
1533 if (Page* page = frame().page()) {
1534 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1535 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1540 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1542 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1543 if (Page* page = frame().page()) {
1544 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1545 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1548 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1549 // why isn't the same check being made here?
1550 updateCanBlitOnScrollRecursively();
1554 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1557 if (useCustomFixedPositionLayoutRect())
1558 return customFixedPositionLayoutRect();
1560 LayoutRect viewportRect = visibleContentRect();
1562 viewportRect.setLocation(toLayoutPoint(scrollOffsetForFixedPosition()));
1563 return viewportRect;
1566 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)
1568 LayoutPoint position;
1569 if (behaviorForFixed == StickToDocumentBounds)
1570 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1572 position = scrollPosition;
1573 position.setY(position.y() - headerHeight);
1576 LayoutSize maxSize = totalContentsSize - visibleContentRect.size();
1578 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1579 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1581 return LayoutSize(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1584 LayoutSize FrameView::scrollOffsetForFixedPosition() const
1586 IntRect visibleContentRect = this->visibleContentRect();
1587 IntSize totalContentsSize = this->totalContentsSize();
1588 IntPoint scrollPosition = this->scrollPosition();
1589 IntPoint scrollOrigin = this->scrollOrigin();
1590 float frameScaleFactor = frame().frameScaleFactor();
1591 ScrollBehaviorForFixedElements behaviorForFixed = scrollBehaviorForFixedElements();
1592 return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), behaviorForFixed, headerHeight(), footerHeight());
1595 float FrameView::yPositionForInsetClipLayer(const FloatPoint& scrollPosition, float topContentInset)
1597 if (!topContentInset)
1600 // The insetClipLayer should not move for negative scroll values.
1601 float scrollY = std::max<float>(0, scrollPosition.y());
1603 if (scrollY >= topContentInset)
1606 return topContentInset - scrollY;
1609 float FrameView::yPositionForHeaderLayer(const FloatPoint& scrollPosition, float topContentInset)
1611 if (!topContentInset)
1614 float scrollY = std::max<float>(0, scrollPosition.y());
1616 if (scrollY >= topContentInset)
1617 return topContentInset;
1622 float FrameView::yPositionForRootContentLayer(const FloatPoint& scrollPosition, float topContentInset, float headerHeight)
1624 return yPositionForHeaderLayer(scrollPosition, topContentInset) + headerHeight;
1627 float FrameView::yPositionForFooterLayer(const FloatPoint& scrollPosition, float topContentInset, float totalContentsHeight, float footerHeight)
1629 return yPositionForHeaderLayer(scrollPosition, topContentInset) + totalContentsHeight - footerHeight;
1633 LayoutRect FrameView::rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements scrollBehavior)
1635 if (fixedElementsLayoutRelativeToFrame)
1636 return visibleContentRect;
1638 // We impose an lower limit on the size (so an upper limit on the scale) of
1639 // the rect used to position fixed objects so that they don't crowd into the
1640 // center of the screen at larger scales.
1641 const float constraintThresholdScale = 1.2;
1643 float maxPostionedObjectsRectScale = std::min(frameScaleFactor, constraintThresholdScale);
1645 LayoutRect viewportConstrainedObjectsRect = visibleContentRect;
1647 if (frameScaleFactor > constraintThresholdScale) {
1648 FloatRect contentRect(FloatPoint(), totalContentsSize);
1649 FloatRect viewportRect = visibleContentRect;
1651 // Scale the rect up from a point that is relative to its position in the viewport.
1652 FloatSize sizeDelta = contentRect.size() - viewportRect.size();
1654 FloatPoint scaleOrigin;
1655 scaleOrigin.setX(contentRect.x() + sizeDelta.width() > 0 ? contentRect.width() * (viewportRect.x() - contentRect.x()) / sizeDelta.width() : 0);
1656 scaleOrigin.setY(contentRect.y() + sizeDelta.height() > 0 ? contentRect.height() * (viewportRect.y() - contentRect.y()) / sizeDelta.height() : 0);
1658 AffineTransform rescaleTransform = AffineTransform::translation(scaleOrigin.x(), scaleOrigin.y());
1659 rescaleTransform.scale(frameScaleFactor / maxPostionedObjectsRectScale, frameScaleFactor / maxPostionedObjectsRectScale);
1660 rescaleTransform = CGAffineTransformTranslate(rescaleTransform, -scaleOrigin.x(), -scaleOrigin.y());
1662 viewportConstrainedObjectsRect = enclosingLayoutRect(rescaleTransform.mapRect(visibleContentRect));
1665 if (scrollBehavior == StickToDocumentBounds) {
1666 LayoutRect documentBounds(LayoutPoint(), totalContentsSize);
1667 viewportConstrainedObjectsRect.intersect(documentBounds);
1670 return viewportConstrainedObjectsRect;
1673 LayoutRect FrameView::viewportConstrainedObjectsRect() const
1675 return rectForViewportConstrainedObjects(visibleContentRect(), totalContentsSize(), frame().frameScaleFactor(), fixedElementsLayoutRelativeToFrame(), scrollBehaviorForFixedElements());
1679 IntPoint FrameView::minimumScrollPosition() const
1681 IntPoint minimumPosition(ScrollView::minimumScrollPosition());
1683 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
1684 minimumPosition.setY(maximumScrollPosition().y());
1686 return minimumPosition;
1689 IntPoint FrameView::maximumScrollPosition() const
1691 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
1693 maximumOffset.clampNegativeToZero();
1695 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
1696 maximumOffset.setY(minimumScrollPosition().y());
1698 return maximumOffset;
1701 bool FrameView::fixedElementsLayoutRelativeToFrame() const
1703 return frame().settings().fixedElementsLayoutRelativeToFrame();
1706 IntPoint FrameView::lastKnownMousePosition() const
1708 return frame().eventHandler().lastKnownMousePosition();
1711 bool FrameView::isHandlingWheelEvent() const
1713 return frame().eventHandler().isHandlingWheelEvent();
1716 bool FrameView::shouldSetCursor() const
1718 Page* page = frame().page();
1719 return page && page->isVisible() && page->focusController().isActive();
1722 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1724 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1725 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1729 const bool isCompositedContentLayer = contentsInCompositedLayer();
1731 // Get the rects of the fixed objects visible in the rectToScroll
1732 Region regionToUpdate;
1733 for (auto& renderer : *m_viewportConstrainedObjects) {
1734 if (!renderer->style().hasViewportConstrainedPosition())
1736 if (renderer->isComposited())
1739 // Fixed items should always have layers.
1740 ASSERT(renderer->hasLayer());
1741 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1743 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1744 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1745 // Don't invalidate for invisible fixed layers.
1749 #if ENABLE(CSS_FILTERS)
1750 if (layer->hasAncestorWithFilterOutsets()) {
1751 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1752 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1756 IntRect updateRect = pixelSnappedIntRect(layer->repaintRectIncludingNonCompositingDescendants());
1757 updateRect = contentsToRootView(updateRect);
1758 if (!isCompositedContentLayer && clipsRepaints())
1759 updateRect.intersect(rectToScroll);
1760 if (!updateRect.isEmpty())
1761 regionToUpdate.unite(updateRect);
1765 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1767 // 2) update the area of fixed objects that has been invalidated
1768 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1769 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1770 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1771 IntRect updateRect = subRectsToUpdate[i];
1772 IntRect scrolledRect = updateRect;
1773 scrolledRect.move(scrollDelta);
1774 updateRect.unite(scrolledRect);
1775 if (isCompositedContentLayer) {
1776 updateRect = rootViewToContents(updateRect);
1777 ASSERT(renderView());
1778 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1781 if (clipsRepaints())
1782 updateRect.intersect(rectToScroll);
1783 hostWindow()->invalidateContentsAndRootView(updateRect);
1789 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1791 if (contentsInCompositedLayer()) {
1792 // FIXME: respect paintsEntireContents()?
1793 IntRect updateRect = visibleContentRect(LegacyIOSDocumentVisibleRect);
1795 // Make sure to "apply" the scale factor here since we're converting from frame view
1796 // coordinates to layer backing coordinates.
1797 updateRect.scale(1 / frame().frameScaleFactor());
1799 ASSERT(renderView());
1800 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect, GraphicsLayer::DoNotClipToLayer);
1803 repaintSlowRepaintObjects();
1805 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
1806 if (isEnclosedInCompositingLayer()) {
1807 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1808 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1809 visibleWidth(), visibleHeight());
1810 frameRenderer->repaintRectangle(rect);
1815 ScrollView::scrollContentsSlowPath(updateRect);
1818 void FrameView::repaintSlowRepaintObjects()
1820 if (!m_slowRepaintObjects)
1823 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
1824 // repaint them after scrolling.
1825 for (auto& renderer : *m_slowRepaintObjects)
1826 renderer->repaintSlowRepaintObject();
1829 // Note that this gets called at painting time.
1830 void FrameView::setIsOverlapped(bool isOverlapped)
1832 if (isOverlapped == m_isOverlapped)
1835 m_isOverlapped = isOverlapped;
1836 updateCanBlitOnScrollRecursively();
1838 if (hasCompositedContentIncludingDescendants()) {
1839 // Overlap can affect compositing tests, so if it changes, we need to trigger
1840 // a layer update in the parent document.
1841 if (Frame* parentFrame = frame().tree().parent()) {
1842 if (RenderView* parentView = parentFrame->contentRenderer()) {
1843 RenderLayerCompositor& compositor = parentView->compositor();
1844 compositor.setCompositingLayersNeedRebuild();
1845 compositor.scheduleCompositingLayerUpdate();
1849 if (RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) {
1850 // We also need to trigger reevaluation for this and all descendant frames,
1851 // since a frame uses compositing if any ancestor is compositing.
1852 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1853 if (RenderView* view = frame->contentRenderer()) {
1854 RenderLayerCompositor& compositor = view->compositor();
1855 compositor.setCompositingLayersNeedRebuild();
1856 compositor.scheduleCompositingLayerUpdate();
1863 bool FrameView::isOverlappedIncludingAncestors() const
1868 if (FrameView* parentView = parentFrameView()) {
1869 if (parentView->isOverlapped())
1876 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1878 if (contentIsOpaque == m_contentIsOpaque)
1881 m_contentIsOpaque = contentIsOpaque;
1882 updateCanBlitOnScrollRecursively();
1885 void FrameView::restoreScrollbar()
1887 setScrollbarsSuppressed(false);
1890 bool FrameView::scrollToFragment(const URL& url)
1892 // If our URL has no ref, then we have no place we need to jump to.
1893 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1894 // and possibly repaint because :target pseudo class may have been
1895 // set (see bug 11321).
1896 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
1899 String fragmentIdentifier = url.fragmentIdentifier();
1900 if (scrollToAnchor(fragmentIdentifier))
1903 // Try again after decoding the ref, based on the document's encoding.
1904 if (TextResourceDecoder* decoder = frame().document()->decoder())
1905 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
1910 bool FrameView::scrollToAnchor(const String& name)
1912 ASSERT(frame().document());
1914 if (!frame().document()->haveStylesheetsLoaded()) {
1915 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1919 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1921 Element* anchorElement = frame().document()->findAnchor(name);
1923 // Setting to null will clear the current target.
1924 frame().document()->setCSSTarget(anchorElement);
1926 if (frame().document()->isSVGDocument()) {
1927 if (SVGSVGElement* svg = toSVGDocument(frame().document())->rootElement()) {
1928 svg->setupInitialView(name, anchorElement);
1934 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1935 if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1938 maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : frame().document());
1940 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1941 if (anchorElement && anchorElement->isFocusable())
1942 frame().document()->setFocusedElement(anchorElement);
1947 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1949 m_maintainScrollPositionAnchor = anchorNode;
1950 if (!m_maintainScrollPositionAnchor)
1953 // We need to update the layout before scrolling, otherwise we could
1954 // really mess things up if an anchor scroll comes at a bad moment.
1955 frame().document()->updateStyleIfNeeded();
1956 // Only do a layout if changes have occurred that make it necessary.
1957 RenderView* renderView = this->renderView();
1958 if (renderView && renderView->needsLayout())
1964 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1966 frame().document()->updateLayoutIgnorePendingStylesheets();
1968 LayoutRect bounds = element->boundingBox();
1969 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
1970 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
1971 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
1974 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1976 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1977 m_maintainScrollPositionAnchor = 0;
1978 ScrollView::setScrollPosition(scrollPoint);
1981 void FrameView::delegatesScrollingDidChange()
1983 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
1984 if (hasCompositedContent())
1985 clearBackingStores();
1988 #if USE(TILED_BACKING_STORE)
1989 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
1991 bool visibleContentSizeDidChange = false;
1992 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
1993 // When the viewport size changes or the content is scaled, we need to
1994 // reposition the fixed and sticky positioned elements.
1995 setViewportConstrainedObjectsNeedLayout();
1996 visibleContentSizeDidChange = true;
1999 IntSize offset = scrollOffset();
2000 IntPoint oldPosition = scrollPosition();
2001 ScrollView::setFixedVisibleContentRect(visibleContentRect);
2002 if (offset != scrollOffset()) {
2003 updateLayerPositionsAfterScrolling();
2004 if (frame().page()->settings().acceleratedCompositingForFixedPositionEnabled())
2005 updateCompositingLayersAfterScrolling();
2006 IntPoint newPosition = scrollPosition();
2007 scrollAnimator()->setCurrentPosition(scrollPosition());
2008 scrollPositionChanged(oldPosition, newPosition);
2010 if (visibleContentSizeDidChange) {
2011 // Update the scroll-bars to calculate new page-step size.
2012 updateScrollbars(scrollOffset());
2014 frame().loader().client().didChangeScrollOffset();
2018 void FrameView::setViewportConstrainedObjectsNeedLayout()
2020 if (!hasViewportConstrainedObjects())
2023 for (auto& renderer : *m_viewportConstrainedObjects)
2024 renderer->setNeedsLayout();
2027 void FrameView::scrollPositionChangedViaPlatformWidget(const IntPoint& oldPosition, const IntPoint& newPosition)
2029 updateLayerPositionsAfterScrolling();
2030 updateCompositingLayersAfterScrolling();
2031 repaintSlowRepaintObjects();
2032 scrollPositionChanged(oldPosition, newPosition);
2035 void FrameView::scrollPositionChanged(const IntPoint& oldPosition, const IntPoint& newPosition)
2037 frame().eventHandler().sendScrollEvent();
2038 frame().eventHandler().dispatchFakeMouseMoveEventSoon();
2040 if (Document* document = frame().document())
2041 document->sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize());
2043 if (RenderView* renderView = this->renderView()) {
2044 renderView->resumePausedImageAnimationsIfNeeded();
2045 if (renderView->usesCompositing())
2046 renderView->compositor().frameViewDidScroll();
2050 void FrameView::updateLayerPositionsAfterScrolling()
2052 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
2053 if (m_layoutPhase == InViewSizeAdjust)
2056 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2057 if (RenderView* renderView = this->renderView()) {
2058 updateWidgetPositions();
2059 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
2064 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
2066 #if ENABLE(ASYNC_SCROLLING)
2067 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
2069 Page* page = frame().page();
2073 if (&page->mainFrame() != &frame())
2076 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
2077 if (!scrollingCoordinator)
2080 if (!scrollingCoordinator->supportsFixedPositionLayers())
2083 if (scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2086 if (inProgrammaticScroll())
2094 void FrameView::updateCompositingLayersAfterScrolling()
2096 if (!shouldUpdateCompositingLayersAfterScrolling())
2099 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2100 if (RenderView* renderView = this->renderView())
2101 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2105 bool FrameView::isRubberBandInProgress() const
2107 if (scrollbarsSuppressed())
2110 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2111 // ScrollingCoordinator::isRubberBandInProgress().
2112 if (Page* page = frame().page()) {
2113 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2114 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously())
2115 return scrollingCoordinator->isRubberBandInProgress();
2119 // If the main thread updates the scroll position for this FrameView, we should return
2120 // ScrollAnimator::isRubberBandInProgress().
2121 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2122 return scrollAnimator->isRubberBandInProgress();
2127 bool FrameView::requestScrollPositionUpdate(const IntPoint& position)
2129 #if ENABLE(ASYNC_SCROLLING)
2130 if (TiledBacking* tiledBacking = this->tiledBacking())
2131 tiledBacking->prepopulateRect(FloatRect(position, visibleContentRect().size()));
2133 if (Page* page = frame().page()) {
2134 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2135 return scrollingCoordinator->requestScrollPositionUpdate(this, position);
2138 UNUSED_PARAM(position);
2144 HostWindow* FrameView::hostWindow() const
2146 if (Page* page = frame().page())
2147 return &page->chrome();
2151 void FrameView::addTrackedRepaintRect(const FloatRect& r)
2153 if (!m_isTrackingRepaints || r.isEmpty())
2156 FloatRect repaintRect = r;
2157 repaintRect.move(-scrollOffset());
2158 m_trackedRepaintRects.append(repaintRect);
2161 void FrameView::repaintContentRectangle(const IntRect& r)
2163 ASSERT(!frame().ownerElement());
2165 if (!shouldUpdate())
2168 ScrollView::repaintContentRectangle(r);
2171 static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderObject& renderer, unsigned countSoFar, unsigned threshold)
2173 // FIXME: Consider writing this using RenderObject::nextInPreOrder() instead of using recursion.
2174 if (renderer.isText())
2175 countSoFar += toRenderText(renderer).text()->length();
2177 for (RenderObject* child = renderer.firstChildSlow(); child; child = child->nextSibling()) {
2178 if (countSoFar >= threshold)
2180 countSoFar = countRenderedCharactersInRenderObjectWithThreshold(*child, countSoFar, threshold);
2185 bool FrameView::renderedCharactersExceed(unsigned threshold)
2187 if (!m_frame->contentRenderer())
2189 return countRenderedCharactersInRenderObjectWithThreshold(*m_frame->contentRenderer(), 0, threshold) >= threshold;
2192 void FrameView::contentsResized()
2194 ScrollView::contentsResized();
2198 void FrameView::fixedLayoutSizeChanged()
2200 // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized().
2201 // An ASSERT is triggered when a view schedules a layout before being attached to a frame.
2202 if (!frame().view())
2204 ScrollView::fixedLayoutSizeChanged();
2207 bool FrameView::shouldLayoutAfterContentsResized() const
2209 return !useFixedLayout() || useCustomFixedPositionLayoutRect();
2212 void FrameView::visibleContentsResized()
2214 // We check to make sure the view is attached to a frame() as this method can
2215 // be triggered before the view is attached by Frame::createView(...) setting
2216 // various values such as setScrollBarModes(...) for example. An ASSERT is
2217 // triggered when a view is layout before being attached to a frame().
2218 if (!frame().view())
2222 if (RenderView* root = m_frame->contentRenderer()) {
2223 if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
2224 setViewportConstrainedObjectsNeedLayout();
2225 // We must eagerly enter compositing mode because fixed position elements
2226 // will not have been made compositing via a preceding style change before
2227 // m_useCustomFixedPositionLayoutRect was true.
2228 root->compositor().enableCompositingMode();
2233 if (shouldLayoutAfterContentsResized() && needsLayout())
2236 if (RenderView* renderView = this->renderView()) {
2237 if (renderView->usesCompositing())
2238 renderView->compositor().frameViewDidChangeSize();
2242 void FrameView::addedOrRemovedScrollbar()
2244 if (RenderView* renderView = this->renderView()) {
2245 if (renderView->usesCompositing())
2246 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2250 void FrameView::disableLayerFlushThrottlingTemporarilyForInteraction()
2252 if (RenderView* view = renderView())
2253 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2256 void FrameView::updateLayerFlushThrottlingInAllFrames()
2258 bool isMainLoadProgressing = frame().page()->progress().isMainLoadProgressing();
2259 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2260 if (RenderView* renderView = frame->contentRenderer())
2261 renderView->compositor().setLayerFlushThrottlingEnabled(isMainLoadProgressing);
2265 void FrameView::adjustTiledBackingCoverage()
2267 if (!m_speculativeTilingEnabled)
2268 enableSpeculativeTilingIfNeeded();
2270 RenderView* renderView = this->renderView();
2271 if (renderView && renderView->layer()->backing())
2272 renderView->layer()->backing()->adjustTiledBackingCoverage();
2274 if (LegacyTileCache* tileCache = legacyTileCache())
2275 tileCache->setSpeculativeTileCreationEnabled(m_speculativeTilingEnabled);
2279 static bool shouldEnableSpeculativeTilingDuringLoading(const FrameView& view)
2281 return view.isVisuallyNonEmpty() && !view.frame().page()->progress().isMainLoadProgressing();
2284 void FrameView::enableSpeculativeTilingIfNeeded()
2286 ASSERT(!m_speculativeTilingEnabled);
2287 if (m_wasScrolledByUser) {
2288 m_speculativeTilingEnabled = true;
2291 if (!shouldEnableSpeculativeTilingDuringLoading(*this))
2293 if (m_speculativeTilingEnableTimer.isActive())
2295 // Delay enabling a bit as load completion may trigger further loading from scripts.
2296 static const double speculativeTilingEnableDelay = 0.5;
2297 m_speculativeTilingEnableTimer.startOneShot(speculativeTilingEnableDelay);
2300 void FrameView::speculativeTilingEnableTimerFired(Timer<FrameView>&)
2302 if (m_speculativeTilingEnabled)
2304 m_speculativeTilingEnabled = shouldEnableSpeculativeTilingDuringLoading(*this);
2305 adjustTiledBackingCoverage();
2308 void FrameView::layoutTimerFired(Timer<FrameView>&)
2310 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2311 if (!frame().document()->ownerElement())
2312 printf("Layout timer fired at %lld\n", frame().document()->elapsedTime().count());
2317 void FrameView::scheduleRelayout()
2319 // FIXME: We should assert the page is not in the page cache, but that is causing
2320 // too many false assertions. See <rdar://problem/7218118>.
2321 ASSERT(frame().view() == this);
2324 m_layoutRoot->markContainingBlocksForLayout(false);
2327 if (!m_layoutSchedulingEnabled)
2331 if (!frame().document()->shouldScheduleLayout())
2333 InspectorInstrumentation::didInvalidateLayout(&frame());
2334 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2335 // Also invalidate parent frame starting from the owner element of this frame.
2336 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2337 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2339 std::chrono::milliseconds delay = frame().document()->minimumLayoutDelay();
2340 if (m_layoutTimer.isActive() && m_delayedLayout && !delay.count())
2341 unscheduleRelayout();
2342 if (m_layoutTimer.isActive())
2345 m_delayedLayout = delay.count();
2347 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2348 if (!frame().document()->ownerElement())
2349 printf("Scheduling layout for %d\n", delay);
2352 m_layoutTimer.startOneShot(delay);
2355 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2357 for (RenderObject* r = descendant; r; r = r->container()) {
2364 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2366 ASSERT(renderView());
2367 RenderView& renderView = *this->renderView();
2369 // Try to catch unnecessary work during render tree teardown.
2370 ASSERT(!renderView.documentBeingDestroyed());
2371 ASSERT(frame().view() == this);
2373 if (renderView.needsLayout()) {
2374 newRelayoutRoot.markContainingBlocksForLayout(false);
2378 if (!layoutPending() && m_layoutSchedulingEnabled) {
2379 std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay();
2380 ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout());
2381 m_layoutRoot = &newRelayoutRoot;
2382 InspectorInstrumentation::didInvalidateLayout(&frame());
2383 m_delayedLayout = delay.count();
2384 m_layoutTimer.startOneShot(delay);
2388 if (m_layoutRoot == &newRelayoutRoot)
2391 if (!m_layoutRoot) {
2392 // Just relayout the subtree.
2393 newRelayoutRoot.markContainingBlocksForLayout(false);
2394 InspectorInstrumentation::didInvalidateLayout(&frame());
2398 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2399 // Keep the current root.
2400 newRelayoutRoot.markContainingBlocksForLayout(false, m_layoutRoot);
2401 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2405 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2406 // Re-root at newRelayoutRoot.
2407 m_layoutRoot->markContainingBlocksForLayout(false, &newRelayoutRoot);
2408 m_layoutRoot = &newRelayoutRoot;
2409 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2410 InspectorInstrumentation::didInvalidateLayout(&frame());
2414 // Just do a full relayout.
2415 m_layoutRoot->markContainingBlocksForLayout(false);
2417 newRelayoutRoot.markContainingBlocksForLayout(false);
2418 InspectorInstrumentation::didInvalidateLayout(&frame());
2421 bool FrameView::layoutPending() const
2423 return m_layoutTimer.isActive();
2426 bool FrameView::needsLayout() const
2428 // This can return true in cases where the document does not have a body yet.
2429 // Document::shouldScheduleLayout takes care of preventing us from scheduling
2430 // layout in that case.
2431 RenderView* renderView = this->renderView();
2432 return layoutPending()
2433 || (renderView && renderView->needsLayout())
2435 || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
2438 void FrameView::setNeedsLayout()
2440 if (m_deferSetNeedsLayouts) {
2441 m_setNeedsLayoutWasDeferred = true;
2445 if (RenderView* renderView = this->renderView())
2446 renderView->setNeedsLayout();
2449 void FrameView::unscheduleRelayout()
2451 if (!m_layoutTimer.isActive())
2454 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2455 if (!frame().document()->ownerElement())
2456 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
2459 m_layoutTimer.stop();
2460 m_delayedLayout = false;
2463 #if ENABLE(REQUEST_ANIMATION_FRAME)
2464 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
2466 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
2467 frame->view()->serviceScrollAnimations();
2468 frame->animation().serviceAnimations();
2471 Vector<RefPtr<Document>> documents;
2472 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext())
2473 documents.append(frame->document());
2475 for (size_t i = 0; i < documents.size(); ++i)
2476 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
2480 bool FrameView::isTransparent() const
2482 return m_isTransparent;
2485 void FrameView::setTransparent(bool isTransparent)
2487 m_isTransparent = isTransparent;
2490 bool FrameView::hasOpaqueBackground() const
2492 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
2495 Color FrameView::baseBackgroundColor() const
2497 return m_baseBackgroundColor;
2500 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
2502 if (!backgroundColor.isValid())
2503 m_baseBackgroundColor = Color::white;
2505 m_baseBackgroundColor = backgroundColor;
2507 recalculateScrollbarOverlayStyle();
2510 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
2512 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2513 if (FrameView* view = frame->view()) {
2514 view->setTransparent(transparent);
2515 view->setBaseBackgroundColor(backgroundColor);
2520 bool FrameView::hasExtendedBackgroundRectForPainting() const
2522 if (!frame().settings().backgroundShouldExtendBeyondPage())
2525 TiledBacking* tiledBacking = this->tiledBacking();
2529 return tiledBacking->hasMargins();
2532 void FrameView::updateExtendBackgroundIfNecessary()
2534 ExtendedBackgroundMode mode = calculateExtendedBackgroundMode();
2535 if (mode == ExtendedBackgroundModeNone)
2538 updateTilesForExtendedBackgroundMode(mode);
2541 FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
2543 // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
2544 // that the background rect needs to be extended for painting. Simple backgrounds can be extended
2545 // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
2546 // such as images, require extending the background rect to continue painting into the extended
2547 // region. This function finds out if it is necessary to extend the background rect for painting.
2550 // <rdar://problem/16201373>
2551 return ExtendedBackgroundModeNone;
2554 if (!frame().settings().backgroundShouldExtendBeyondPage())
2555 return ExtendedBackgroundModeNone;
2557 if (!frame().isMainFrame())
2558 return ExtendedBackgroundModeNone;
2560 Document* document = frame().document();
2562 return ExtendedBackgroundModeNone;
2564 auto documentElement = document->documentElement();
2565 auto documentElementRenderer = documentElement ? documentElement->renderer() : nullptr;
2566 if (!documentElementRenderer)
2567 return ExtendedBackgroundModeNone;
2569 auto& renderer = documentElementRenderer->rendererForRootBackground();
2570 if (!renderer.style().hasBackgroundImage())
2571 return ExtendedBackgroundModeNone;
2573 ExtendedBackgroundMode mode = ExtendedBackgroundModeNone;
2575 if (renderer.style().backgroundRepeatX() == RepeatFill)
2576 mode |= ExtendedBackgroundModeHorizontal;
2577 if (renderer.style().backgroundRepeatY() == RepeatFill)
2578 mode |= ExtendedBackgroundModeVertical;
2583 void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
2585 if (!frame().settings().backgroundShouldExtendBeyondPage())
2588 RenderView* renderView = this->renderView();
2592 RenderLayerBacking* backing = renderView->layer()->backing();
2596 TiledBacking* tiledBacking = backing->graphicsLayer()->tiledBacking();
2600 ExtendedBackgroundMode existingMode = ExtendedBackgroundModeNone;
2601 if (tiledBacking->hasVerticalMargins())
2602 existingMode |= ExtendedBackgroundModeVertical;
2603 if (tiledBacking->hasHorizontalMargins())
2604 existingMode |= ExtendedBackgroundModeHorizontal;
2606 if (existingMode == mode)
2609 renderView->compositor().setRootExtendedBackgroundColor(mode == ExtendedBackgroundModeAll ? Color() : documentBackgroundColor());
2610 backing->setTiledBackingHasMargins(mode & ExtendedBackgroundModeHorizontal, mode & ExtendedBackgroundModeVertical);
2613 IntRect FrameView::extendedBackgroundRectForPainting() const
2615 TiledBacking* tiledBacking = this->tiledBacking();
2619 RenderView* renderView = this->renderView();
2623 LayoutRect extendedRect = renderView->unextendedBackgroundRect(renderView);
2624 if (!tiledBacking->hasMargins())
2625 return pixelSnappedIntRect(extendedRect);
2627 extendedRect.moveBy(LayoutPoint(-tiledBacking->leftMarginWidth(), -tiledBacking->topMarginHeight()));
2628 extendedRect.expand(LayoutSize(tiledBacking->leftMarginWidth() + tiledBacking->rightMarginWidth(), tiledBacking->topMarginHeight() + tiledBacking->bottomMarginHeight()));
2629 return pixelSnappedIntRect(extendedRect);
2632 bool FrameView::shouldUpdateWhileOffscreen() const
2634 return m_shouldUpdateWhileOffscreen;
2637 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
2639 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
2642 bool FrameView::shouldUpdate() const
2644 if (isOffscreen() && !shouldUpdateWhileOffscreen())
2649 void FrameView::scrollToAnchor()
2651 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
2655 if (!anchorNode->renderer())
2659 if (anchorNode != frame().document())
2660 rect = anchorNode->boundingBox();
2662 // Scroll nested layers and frames to reveal the anchor.
2663 // Align to the top and to the closest side (this matches other browsers).
2664 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
2666 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
2667 cache->handleScrolledToAnchor(anchorNode.get());
2669 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
2670 m_maintainScrollPositionAnchor = anchorNode;
2673 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
2675 // No need to update if it's already crashed or known to be missing.
2676 if (embeddedObject.isPluginUnavailable())
2679 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
2681 if (embeddedObject.isSnapshottedPlugIn()) {
2682 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
2683 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2684 pluginElement.checkSnapshotStatus();
2689 auto weakRenderer = embeddedObject.createWeakPtr();
2691 // FIXME: This could turn into a real virtual dispatch if we defined
2692 // updateWidget(PluginCreationOption) on HTMLElement.
2693 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element) || isHTMLAppletElement(element)) {
2694 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2695 if (pluginElement.needsCheckForSizeChange()) {
2696 pluginElement.checkSnapshotStatus();
2699 if (pluginElement.needsWidgetUpdate())
2700 pluginElement.updateWidget(CreateAnyWidgetType);
2702 ASSERT_NOT_REACHED();
2704 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
2708 embeddedObject.updateWidgetPosition();
2711 bool FrameView::updateEmbeddedObjects()
2713 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
2716 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
2718 // Insert a marker for where we should stop.
2719 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
2720 m_embeddedObjectsToUpdate->add(nullptr);
2722 while (!m_embeddedObjectsToUpdate->isEmpty()) {
2723 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
2724 if (!embeddedObject)
2726 updateEmbeddedObject(*embeddedObject);
2729 return m_embeddedObjectsToUpdate->isEmpty();
2732 void FrameView::updateEmbeddedObjectsTimerFired(Timer<FrameView>*)
2734 RefPtr<FrameView> protect(this);
2735 m_updateEmbeddedObjectsTimer.stop();
2736 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
2737 if (updateEmbeddedObjects())
2742 void FrameView::flushAnyPendingPostLayoutTasks()
2744 if (m_postLayoutTasksTimer.isActive())
2745 performPostLayoutTasks();
2746 if (m_updateEmbeddedObjectsTimer.isActive())
2747 updateEmbeddedObjectsTimerFired(nullptr);
2750 void FrameView::performPostLayoutTasks()
2752 // FIXME: We should not run any JavaScript code in this function.
2754 m_postLayoutTasksTimer.stop();
2756 frame().selection().layoutDidChange();
2758 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement())
2759 fireLayoutRelatedMilestonesIfNeeded();
2762 // Only send layout-related delegate callbacks synchronously for the main frame to
2763 // avoid re-entering layout for the main frame while delivering a layout-related delegate
2764 // callback for a subframe.
2765 if (frame().isMainFrame())
2766 frame().page()->chrome().client().didLayout();
2769 #if ENABLE(FONT_LOAD_EVENTS)
2770 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
2771 frame().document()->fontloader()->didLayout();
2774 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
2775 // with didLayout(LayoutMilestones).
2776 frame().loader().client().dispatchDidLayout();
2778 updateWidgetPositions();
2780 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
2781 // is called through the post layout timer.
2782 Ref<FrameView> protect(*this);
2784 m_updateEmbeddedObjectsTimer.startOneShot(0);
2786 if (auto* page = frame().page()) {
2787 if (auto* scrollingCoordinator = page->scrollingCoordinator())
2788 scrollingCoordinator->frameViewLayoutUpdated(this);
2791 if (RenderView* renderView = this->renderView()) {
2792 if (renderView->usesCompositing())
2793 renderView->compositor().frameViewDidLayout();
2798 sendResizeEventIfNeeded();
2801 IntSize FrameView::sizeForResizeEvent() const
2804 if (m_useCustomSizeForResizeEvent)
2805 return m_customSizeForResizeEvent;
2807 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
2808 return fixedLayoutSize();
2809 return visibleContentRectIncludingScrollbars().size();
2812 void FrameView::sendResizeEventIfNeeded()
2814 if (isInLayout() || needsLayout())
2817 RenderView* renderView = this->renderView();
2818 if (!renderView || renderView->printing())
2821 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
2824 IntSize currentSize = sizeForResizeEvent();
2825 float currentZoomFactor = renderView->style().zoom();
2827 if (currentSize == m_lastViewportSize && currentZoomFactor == m_lastZoomFactor)
2830 m_lastViewportSize = currentSize;
2831 m_lastZoomFactor = currentZoomFactor;
2837 // Don't send the resize event if the document is loading. Some pages automatically reload
2838 // when the window is resized; Safari on iOS often resizes the window while setting up its
2839 // viewport. This obviously can cause problems.
2840 if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
2841 if (documentLoader->isLoadingInAPISense())
2846 bool isMainFrame = frame().isMainFrame();
2847 bool canSendResizeEventSynchronously = isMainFrame && !m_shouldAutoSize;
2849 RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
2850 if (canSendResizeEventSynchronously)
2851 frame().document()->dispatchWindowEvent(resizeEvent.release());
2853 // FIXME: Queueing this event for an unpredictable time in the future seems
2854 // intrinsically racy. By the time this resize event fires, the frame might
2855 // be resized again, so we could end up with two resize events for the same size.
2856 frame().document()->enqueueWindowEvent(resizeEvent.release());
2859 #if ENABLE(INSPECTOR)
2860 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
2861 if (Page* page = frame().page()) {
2862 if (InspectorClient* inspectorClient = page->inspectorController().inspectorClient())
2863 inspectorClient->didResizeMainFrame(&frame());
2869 void FrameView::willStartLiveResize()
2871 ScrollView::willStartLiveResize();
2872 adjustTiledBackingCoverage();
2875 void FrameView::willEndLiveResize()
2877 ScrollView::willEndLiveResize();
2878 adjustTiledBackingCoverage();
2881 void FrameView::postLayoutTimerFired(Timer<FrameView>&)
2883 performPostLayoutTasks();
2886 void FrameView::autoSizeIfEnabled()
2888 if (!m_shouldAutoSize)
2894 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2896 Document* document = frame().document();
2900 RenderView* documentView = document->renderView();
2901 Element* documentElement = document->documentElement();
2902 if (!documentView || !documentElement)
2905 // Start from the minimum size and allow it to grow.
2906 resize(m_minAutoSize.width(), m_minAutoSize.height());
2908 IntSize size = frameRect().size();
2910 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2911 // which may result in a height change during the second iteration.
2912 for (int i = 0; i < 2; i++) {
2913 // Update various sizes including contentsSize, scrollHeight, etc.
2914 document->updateLayoutIgnorePendingStylesheets();
2915 int width = documentView->minPreferredLogicalWidth();
2916 int height = documentView->documentRect().height();
2917 IntSize newSize(width, height);
2919 // Check to see if a scrollbar is needed for a given dimension and
2920 // if so, increase the other dimension to account for the scrollbar.
2921 // Since the dimensions are only for the view rectangle, once a
2922 // dimension exceeds the maximum, there is no need to increase it further.
2923 if (newSize.width() > m_maxAutoSize.width()) {
2924 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2925 if (!localHorizontalScrollbar)
2926 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2927 if (!localHorizontalScrollbar->isOverlayScrollbar())
2928 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
2930 // Don't bother checking for a vertical scrollbar because the width is at
2931 // already greater the maximum.
2932 } else if (newSize.height() > m_maxAutoSize.height()) {
2933 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
2934 if (!localVerticalScrollbar)
2935 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
2936 if (!localVerticalScrollbar->isOverlayScrollbar())
2937 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
2939 // Don't bother checking for a horizontal scrollbar because the height is
2940 // already greater the maximum.
2943 // Ensure the size is at least the min bounds.
2944 newSize = newSize.expandedTo(m_minAutoSize);
2946 // Bound the dimensions by the max bounds and determine what scrollbars to show.
2947 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
2948 if (newSize.width() > m_maxAutoSize.width()) {
2949 newSize.setWidth(m_maxAutoSize.width());
2950 horizonalScrollbarMode = ScrollbarAlwaysOn;
2952 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
2953 if (newSize.height() > m_maxAutoSize.height()) {
2954 newSize.setHeight(m_maxAutoSize.height());
2955 verticalScrollbarMode = ScrollbarAlwaysOn;
2958 if (newSize == size)
2961 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
2962 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
2963 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
2964 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
2967 resize(newSize.width(), newSize.height());
2968 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
2969 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
2970 setVerticalScrollbarLock(false);
2971 setHorizontalScrollbarLock(false);
2972 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
2975 m_autoSizeContentSize = contentsSize();
2977 if (m_autoSizeFixedMinimumHeight) {
2978 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
2979 document->updateLayoutIgnorePendingStylesheets();
2982 m_didRunAutosize = true;
2985 void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
2987 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
2990 m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
2995 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2997 if (!m_viewportRenderer)
3000 if (m_overflowStatusDirty) {
3001 m_horizontalOverflow = horizontalOverflow;
3002 m_verticalOverflow = verticalOverflow;
3003 m_overflowStatusDirty = false;
3007 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
3008 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
3010 if (horizontalOverflowChanged || verticalOverflowChanged) {
3011 m_horizontalOverflow = horizontalOverflow;
3012 m_verticalOverflow = verticalOverflow;
3014 RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
3015 verticalOverflowChanged, verticalOverflow);
3016 overflowEvent->setTarget(m_viewportRenderer->element());
3018 frame().document()->enqueueOverflowEvent(overflowEvent.release());
3023 const Pagination& FrameView::pagination() const
3025 if (m_pagination != Pagination())
3026 return m_pagination;
3028 if (frame().isMainFrame())
3029 return frame().page()->pagination();
3031 return m_pagination;
3034 void FrameView::setPagination(const Pagination& pagination)
3036 if (m_pagination == pagination)
3039 m_pagination = pagination;
3041 frame().document()->styleResolverChanged(DeferRecalcStyle);
3044 IntRect FrameView::windowClipRect(bool clipToContents) const
3046 ASSERT(frame().view() == this);
3048 if (paintsEntireContents())
3049 return IntRect(IntPoint(), totalContentsSize());
3051 // Set our clip rect to be our contents.
3054 clipRect = contentsToWindow(visibleContentRect(LegacyIOSDocumentVisibleRect));
3056 clipRect = contentsToWindow(visibleContentRectIncludingScrollbars(LegacyIOSDocumentVisibleRect));
3057 if (!frame().ownerElement())
3060 // Take our owner element and get its clip rect.
3061 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
3062 if (FrameView* parentView = ownerElement->document().view())
3063 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
3067 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
3069 // The renderer can sometimes be null when style="display:none" interacts
3070 // with external content and plugins.
3071 if (!ownerElement->renderer())
3072 return windowClipRect();
3074 // If we have no layer, just return our window clip rect.
3075 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
3076 if (!enclosingLayer)
3077 return windowClipRect();
3079 // Apply the clip from the layer.
3081 if (clipToLayerContents)
3082 clipRect = pixelSnappedIntRect(enclosingLayer->childrenClipRect());
3084 clipRect = pixelSnappedIntRect(enclosingLayer->selfClipRect());
3085 clipRect = contentsToWindow(clipRect);
3086 return intersection(clipRect, windowClipRect());
3089 bool FrameView::isActive() const
3091 Page* page = frame().page();
3092 return page && page->focusController().isActive();
3095 bool FrameView::updatesScrollLayerPositionOnMainThread() const
3097 if (Page* page = frame().page()) {
3098 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
3099 return scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously();
3105 void FrameView::scrollTo(const IntSize& newOffset)
3107 LayoutSize offset = scrollOffset();
3108 IntPoint oldPosition = scrollPosition();
3109 ScrollView::scrollTo(newOffset);
3110 if (offset != scrollOffset())
3111 scrollPositionChanged(oldPosition, scrollPosition());
3112 frame().loader().client().didChangeScrollOffset();
3115 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
3117 // Add in our offset within the FrameView.
3118 IntRect dirtyRect = rect;
3119 dirtyRect.moveBy(scrollbar->location());
3120 invalidateRect(dirtyRect);
3123 IntRect FrameView::windowResizerRect() const
3125 if (Page* page = frame().page())
3126 return page->chrome().windowResizerRect();
3130 float FrameView::visibleContentScaleFactor() const
3132 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3135 return frame().page()->pageScaleFactor();
3138 void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3140 if (!frame().isMainFrame())
3143 frame().page()->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3146 ScrollableArea* FrameView::enclosingScrollableArea() const
3148 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3152 IntRect FrameView::scrollableAreaBoundingBox() const
3154 RenderWidget* ownerRenderer = frame().ownerRenderer();
3158 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3161 bool FrameView::isScrollable()
3164 // 1) If there an actual overflow.
3165 // 2) display:none or visibility:hidden set to self or inherited.
3166 // 3) overflow{-x,-y}: hidden;
3167 // 4) scrolling: no;
3170 IntSize totalContentsSize = this->totalContentsSize();
3171 IntSize visibleContentSize = visibleContentRect(LegacyIOSDocumentVisibleRect).size();
3172 if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width()))
3176 HTMLFrameOwnerElement* owner = frame().ownerElement();
3177 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3181 ScrollbarMode horizontalMode;
3182 ScrollbarMode verticalMode;
3183 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3184 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3190 void FrameView::updateScrollableAreaSet()
3192 // That ensures that only inner frames are cached.
3193 FrameView* parentFrameView = this->parentFrameView();
3194 if (!parentFrameView)
3197 if (!isScrollable()) {
3198 parentFrameView->removeScrollableArea(this);
3202 parentFrameView->addScrollableArea(this);
3205 bool FrameView::shouldSuspendScrollAnimations() const
3207 return frame().loader().state() != FrameStateComplete;
3210 void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate)
3212 if (!frame().isMainFrame())
3215 frame().page()->chrome().client().recommendedScrollbarStyleDidChange(newStyle);
3218 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
3221 void FrameView::notifyPageThatContentAreaWillPaint() const
3223 Page* page = frame().page();
3227 contentAreaWillPaint();
3229 if (!m_scrollableAreas)
3232 for (auto& scrollableArea : *m_scrollableAreas)
3233 scrollableArea->contentAreaWillPaint();
3236 bool FrameView::scrollAnimatorEnabled() const
3238 #if ENABLE(SMOOTH_SCROLLING)
3239 if (Page* page = frame().page())
3240 return page->settings().scrollAnimatorEnabled();
3246 #if ENABLE(DASHBOARD_SUPPORT)
3247 void FrameView::updateAnnotatedRegions()
3249 Document* document = frame().document();
3250 if (!document->hasAnnotatedRegions())
3252 Vector<AnnotatedRegionValue> newRegions;
3253 document->renderBox()->collectAnnotatedRegions(newRegions);
3254 if (newRegions == document->annotatedRegions())
3256 document->setAnnotatedRegions(newRegions);
3257 Page* page = frame().page();
3260 page->chrome().client().annotatedRegionsChanged();
3264 void FrameView::updateScrollCorner()
3266 RenderElement* renderer = 0;
3267 RefPtr<RenderStyle> cornerStyle;
3268 IntRect cornerRect = scrollCornerRect();
3270 if (!cornerRect.isEmpty()) {
3271 // Try the <body> element first as a scroll corner source.
3272 Document* doc = frame().document();
3273 Element* body = doc ? doc->body() : 0;
3274 if (body && body->renderer()) {
3275 renderer = body->renderer();
3276 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3280 // If the <body> didn't have a custom style, then the root element might.
3281 Element* docElement = doc ? doc->documentElement() : 0;
3282 if (docElement && docElement->renderer()) {
3283 renderer = docElement->renderer();
3284 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3289 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
3290 if (RenderWidget* renderer = frame().ownerRenderer())
3291 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3296 m_scrollCorner = nullptr;
3298 if (!m_scrollCorner) {
3299 m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer->document(), cornerStyle.releaseNonNull());
3300 m_scrollCorner->initializeStyle();
3302 m_scrollCorner->setStyle(cornerStyle.releaseNonNull());
3303 invalidateScrollCorner(cornerRect);
3306 ScrollView::updateScrollCorner();
3309 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
3311 if (context->updatingControlTints()) {
3312 updateScrollCorner();
3316 if (m_scrollCorner) {
3317 if (frame().isMainFrame())
3318 context->fillRect(cornerRect, baseBackgroundColor(), ColorSpaceDeviceRGB);
3319 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
3323 ScrollView::paintScrollCorner(context, cornerRect);
3326 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
3328 if (bar->isCustomScrollbar() && frame().isMainFrame()) {
3329 IntRect toFill = bar->frameRect();
3330 toFill.intersect(rect);
3331 context->fillRect(toFill, baseBackgroundColor(), ColorSpaceDeviceRGB);
3334 ScrollView::paintScrollbar(context, bar, rect);
3337 Color FrameView::documentBackgroundColor() const
3339 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
3340 // the document and the body against the base background color of the frame view.
3341 // Background images are unfortunately impractical to include.
3343 // Return invalid Color objects whenever there is insufficient information.
3344 if (!frame().document())
3347 Element* htmlElement = frame().document()->documentElement();
3348 Element* bodyElement = frame().document()->body();
3350 // Start with invalid colors.
3351 Color htmlBackgroundColor;
3352 Color bodyBackgroundColor;
3353 if (htmlElement && htmlElement->renderer())
3354 htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3355 if (bodyElement && bodyElement->renderer())
3356 bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3358 if (!bodyBackgroundColor.isValid()) {
3359 if (!htmlBackgroundColor.isValid())
3361 return baseBackgroundColor().blend(htmlBackgroundColor);
3364 if (!htmlBackgroundColor.isValid())
3365 return baseBackgroundColor().blend(bodyBackgroundColor);
3367 // We take the aggregate of the base background color
3368 // the <html> background color, and the <body>
3369 // background color to find the document color. The
3370 // addition of the base background color is not
3371 // technically part of the document background, but it
3372 // otherwise poses problems when the aggregate is not
3374 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor);
3377 bool FrameView::hasCustomScrollbars() const
3379 for (auto& widget : children()) {
3380 if (widget->isFrameView()) {
3381 if (toFrameView(*widget).hasCustomScrollbars())
3383 } else if (widget->isScrollbar()) {
3384 if (toScrollbar(*widget).isCustomScrollbar())
3392 FrameView* FrameView::parentFrameView() const
3397 if (Frame* parentFrame = frame().tree().parent())
3398 return parentFrame->view();
3403 bool FrameView::isInChildFrameWithFrameFlattening() const
3405 if (!parent() || !frame().ownerElement())
3408 // Frame flattening applies when the owner element is either in a frameset or
3409 // an iframe with flattening parameters.
3410 if (frame().ownerElement()->hasTagName(iframeTag)) {
3411 RenderIFrame* iframeRenderer = toRenderIFrame(frame().ownerElement()->renderWidget());
3412 if (iframeRenderer->flattenFrame())
3416 if (!frameFlatteningEnabled())
3419 if (frame().ownerElement()->hasTagName(frameTag))
3425 void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree)
3427 // When we start a layout at the child level as opposed to the topmost frame view and this child
3428 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
3429 // will hit this view eventually.
3430 FrameView* parentView = parentFrameView();
3434 // In the middle of parent layout, no need to restart from topmost.
3435 if (parentView->m_nestedLayoutCount)
3438 // Parent tree is clean. Starting layout from it would have no effect.
3439 if (!parentView->needsLayout())
3442 while (parentView->parentFrameView())
3443 parentView = parentView->parentFrameView();
3445 parentView->layout(allowSubtree);
3447 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
3448 ASSERT_UNUSED(root, !root->needsLayout());
3451 void FrameView::updateControlTints()
3453 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
3454 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
3455 // This is only done if the theme supports control tinting. It's up to the theme and platform
3456 // to define when controls get the tint and to call this function when that changes.
3458 // Optimize the common case where we bring a window to the front while it's still empty.
3459 if (frame().document()->url().isEmpty())
3462 RenderView* renderView = this->renderView();
3463 if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars())
3464 paintControlTints();
3467 void FrameView::paintControlTints()
3471 PlatformGraphicsContext* const noContext = 0;
3472 GraphicsContext context(noContext);
3473 context.setUpdatingControlTints(true);
3474 if (platformWidget()) {
3475 // FIXME: consult paintsEntireContents().
3476 paintContents(&context, visibleContentRect(LegacyIOSDocumentVisibleRect));
3478 paint(&context, frameRect());
3481 bool FrameView::wasScrolledByUser() const
3483 return m_wasScrolledByUser;
3486 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
3488 if (m_inProgrammaticScroll)
3490 m_maintainScrollPositionAnchor = 0;
3491 if (m_wasScrolledByUser == wasScrolledByUser)
3493 m_wasScrolledByUser = wasScrolledByUser;
3494 adjustTiledBackingCoverage();
3497 void FrameView::willPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3499 Document* document = frame().document();
3501 if (!context->paintingDisabled())
3502 InspectorInstrumentation::willPaint(renderView());
3504 paintingState.isTopLevelPainter = !sCurrentPaintTimeStamp;
3506 if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure()) {
3507 LOG(MemoryPressure, "Under memory pressure: %s", WTF_PRETTY_FUNCTION);
3509 // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since
3510 // we might need some live bitmaps on painting.
3511 memoryCache()->prune();
3514 if (paintingState.isTopLevelPainter)
3515 sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
3517 paintingState.paintBehavior = m_paintBehavior;
3519 if (FrameView* parentView = parentFrameView()) {
3520 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
3521 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3524 if (m_paintBehavior == PaintBehaviorNormal)
3525 document->markers().invalidateRenderedRectsForMarkersInRect(dirtyRect);
3527 if (document->printing())
3528 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3530 paintingState.isFlatteningPaintOfRootFrame = (m_paintBehavior & PaintBehaviorFlattenCompositingLayers) && !frame().ownerElement();
3531 if (paintingState.isFlatteningPaintOfRootFrame)
3532 notifyWidgetsInAllFrames(WillPaintFlattened);
3534 ASSERT(!m_isPainting);
3535 m_isPainting = true;
3538 void FrameView::didPaintContents(GraphicsContext* context, const IntRect& dirtyRect, PaintingState& paintingState)
3540 m_isPainting = false;
3542 if (paintingState.isFlatteningPaintOfRootFrame)
3543 notifyWidgetsInAllFrames(DidPaintFlattened);
3545 m_paintBehavior = paintingState.paintBehavior;
3546 m_lastPaintTime = monotonicallyIncreasingTime();
3548 // Painting can lead to decoding of large amounts of bitmaps
3549 // If we are low on memory, wipe them out after the paint.
3550 if (paintingState.isTopLevelPainter && memoryPressureHandler().isUnderMemoryPressure())
3551 memoryCache()->pruneLiveResources(true);
3553 // Regions may have changed as a result of the visibility/z-index of element changing.
3554 #if ENABLE(DASHBOARD_SUPPORT)
3555 if (frame().document()->annotatedRegionsDirty())
3556 updateAnnotatedRegions();
3559 if (paintingState.isTopLevelPainter)
3560 sCurrentPaintTimeStamp = 0;
3562 if (!context->paintingDisabled()) {
3563 InspectorInstrumentation::didPaint(renderView(), context, dirtyRect);
3564 // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623
3565 firePaintRelatedMilestonesIfNeeded();
3569 void FrameView::paintContents(GraphicsContext* context, const IntRect& dirtyRect)
3573 if (frame().document()->printing())
3574 fillWithRed = false; // Printing, don't fill with red (can't remember why).
3575 else if (frame().ownerElement())
3576 fillWithRed = false; // Subframe, don't fill with red.
3577 else if (isTransparent())
3578 fillWithRed = false; // Transparent, don't fill with red.
3579 else if (m_paintBehavior & PaintBehaviorSelectionOnly)
3580 fillWithRed = false; // Selections are transparent, don't fill with red.
3581 else if (m_nodeToDraw)
3582 fillWithRed = false; // Element images are transparent, don't fill with red.
3587 context->fillRect(dirtyRect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
3590 RenderView* renderView = this->renderView();
3592 LOG_ERROR("called FrameView::paint with nil renderer");
3596 ASSERT(!needsLayout());
3600 PaintingState paintingState;
3601 willPaintContents(context, dirtyRect, paintingState);
3603 FontCachePurgePreventer fontCachePurgePreventer;
3605 // m_nodeToDraw is used to draw only one element (and its descendants)
3606 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
3607 RenderLayer* rootLayer = renderView->layer();
3610 RenderElement::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(&rootLayer->renderer());
3613 rootLayer->paint(context, dirtyRect, m_paintBehavior, eltRenderer);
3614 if (rootLayer->containsDirtyOverlayScrollbars())