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"
57 #include "MainFrame.h"
58 #include "OverflowEvent.h"
59 #include "ProgressTracker.h"
60 #include "RenderEmbeddedObject.h"
61 #include "RenderFullScreen.h"
62 #include "RenderIFrame.h"
63 #include "RenderLayer.h"
64 #include "RenderLayerBacking.h"
65 #include "RenderScrollbar.h"
66 #include "RenderScrollbarPart.h"
67 #include "RenderStyle.h"
68 #include "RenderTheme.h"
69 #include "RenderView.h"
70 #include "RenderWidget.h"
71 #include "ScrollAnimator.h"
72 #include "ScrollingCoordinator.h"
74 #include "StyleResolver.h"
75 #include "TextResourceDecoder.h"
76 #include "TextStream.h"
78 #include <wtf/CurrentTime.h>
80 #include <wtf/TemporaryChange.h>
82 #if USE(ACCELERATED_COMPOSITING)
83 #include "RenderLayerCompositor.h"
84 #include "TiledBacking.h"
88 #include "RenderSVGRoot.h"
89 #include "SVGDocument.h"
90 #include "SVGSVGElement.h"
93 #if USE(TILED_BACKING_STORE)
94 #include "TiledBackingStore.h"
97 #if ENABLE(TEXT_AUTOSIZING)
98 #include "TextAutosizer.h"
103 using namespace HTMLNames;
105 double FrameView::sCurrentPaintTimeStamp = 0.0;
108 // REPAINT_THROTTLING now chooses default values for throttling parameters.
109 // Should be removed when applications start using runtime configuration.
110 #if ENABLE(REPAINT_THROTTLING)
112 double FrameView::s_normalDeferredRepaintDelay = 0.016;
113 // Negative value would mean that first few repaints happen without a delay
114 double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0;
115 // The delay grows on each repaint to this maximum value
116 double FrameView::s_maxDeferredRepaintDelayDuringLoading = 2.5;
117 // On each repaint the delay increses by this amount
118 double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0.5;
120 // FIXME: Repaint throttling could be good to have on all platform.
121 // The balance between CPU use and repaint frequency will need some tuning for desktop.
122 // More hooks may be needed to reset the delay on things like GIF and CSS animations.
123 double FrameView::s_normalDeferredRepaintDelay = 0;
124 double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0;
125 double FrameView::s_maxDeferredRepaintDelayDuringLoading = 0;
126 double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0;
129 // The maximum number of updateEmbeddedObjects iterations that should be done before returning.
130 static const unsigned maxUpdateEmbeddedObjectsIterations = 2;
132 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
134 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
135 if (didFullRepaint) {
136 flags &= ~RenderLayer::CheckForRepaint;
137 flags |= RenderLayer::NeedsFullRepaintInBacking;
139 if (isRelayoutingSubtree && layer->isPaginated())
140 flags |= RenderLayer::UpdatePagination;
144 Pagination::Mode paginationModeForRenderStyle(const RenderStyle& style)
146 EOverflow overflow = style.overflowY();
147 if (overflow != OPAGEDX && overflow != OPAGEDY)
148 return Pagination::Unpaginated;
150 bool isHorizontalWritingMode = style.isHorizontalWritingMode();
151 TextDirection textDirection = style.direction();
152 WritingMode writingMode = style.writingMode();
154 // paged-x always corresponds to LeftToRightPaginated or RightToLeftPaginated. If the WritingMode
155 // is horizontal, then we use TextDirection to choose between those options. If the WritingMode
156 // is vertical, then the direction of the verticality dictates the choice.
157 if (overflow == OPAGEDX) {
158 if ((isHorizontalWritingMode && textDirection == LTR) || writingMode == LeftToRightWritingMode)
159 return Pagination::LeftToRightPaginated;
160 return Pagination::RightToLeftPaginated;
163 // paged-y always corresponds to TopToBottomPaginated or BottomToTopPaginated. If the WritingMode
164 // is horizontal, then the direction of the horizontality dictates the choice. If the WritingMode
165 // is vertical, then we use TextDirection to choose between those options.
166 if (writingMode == TopToBottomWritingMode || (!isHorizontalWritingMode && textDirection == RTL))
167 return Pagination::TopToBottomPaginated;
168 return Pagination::BottomToTopPaginated;
171 FrameView::FrameView(Frame& frame)
173 , m_canHaveScrollbars(true)
174 , m_layoutTimer(this, &FrameView::layoutTimerFired)
176 , m_layoutPhase(OutsideLayout)
177 , m_inSynchronousPostLayout(false)
178 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
179 , m_isTransparent(false)
180 , m_baseBackgroundColor(Color::white)
181 , m_mediaType("screen")
182 , m_overflowStatusDirty(true)
183 , m_viewportRenderer(0)
184 , m_wasScrolledByUser(false)
185 , m_inProgrammaticScroll(false)
186 , m_safeToPropagateScrollToParent(true)
187 , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired)
188 , m_isTrackingRepaints(false)
189 , m_shouldUpdateWhileOffscreen(true)
190 , m_deferSetNeedsLayouts(0)
191 , m_setNeedsLayoutWasDeferred(false)
193 , m_shouldAutoSize(false)
194 , m_inAutoSize(false)
195 , m_didRunAutosize(false)
196 , m_autoSizeFixedMinimumHeight(0)
199 , m_milestonesPendingPaint(0)
200 , m_visualUpdatesAllowedByClient(true)
201 , m_scrollPinningBehavior(DoNotPin)
205 if (frame.isMainFrame()) {
206 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
207 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAutomatic);
211 PassRefPtr<FrameView> FrameView::create(Frame& frame)
213 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
215 return view.release();
218 PassRefPtr<FrameView> FrameView::create(Frame& frame, const IntSize& initialSize)
220 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
221 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
223 return view.release();
226 FrameView::~FrameView()
228 if (m_postLayoutTasksTimer.isActive())
229 m_postLayoutTasksTimer.stop();
231 removeFromAXObjectCache();
234 // Custom scrollbars should already be destroyed at this point
235 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
236 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
238 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
239 setHasVerticalScrollbar(false);
241 ASSERT(!m_scrollCorner);
243 ASSERT(frame().view() != this || !frame().contentRenderer());
246 void FrameView::reset()
248 m_cannotBlitToWindow = false;
249 m_isOverlapped = false;
250 m_contentIsOpaque = false;
253 m_layoutTimer.stop();
255 m_delayedLayout = false;
256 m_needsFullRepaint = true;
257 m_layoutSchedulingEnabled = true;
258 m_layoutPhase = OutsideLayout;
259 m_inSynchronousPostLayout = false;
261 m_nestedLayoutCount = 0;
262 m_postLayoutTasksTimer.stop();
263 m_firstLayout = true;
264 m_firstLayoutCallbackPending = false;
265 m_wasScrolledByUser = false;
266 m_safeToPropagateScrollToParent = true;
267 m_lastViewportSize = IntSize();
268 m_lastZoomFactor = 1.0f;
269 m_deferringRepaints = 0;
271 m_repaintRects.clear();
272 m_deferredRepaintDelay = s_initialDeferredRepaintDelayDuringLoading;
273 m_deferredRepaintTimer.stop();
274 m_isTrackingRepaints = false;
275 m_trackedRepaintRects.clear();
277 m_paintBehavior = PaintBehaviorNormal;
278 m_isPainting = false;
279 m_visuallyNonEmptyCharacterCount = 0;
280 m_visuallyNonEmptyPixelCount = 0;
281 m_isVisuallyNonEmpty = false;
282 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
283 m_maintainScrollPositionAnchor = 0;
286 void FrameView::removeFromAXObjectCache()
288 if (AXObjectCache* cache = axObjectCache())
292 void FrameView::resetScrollbars()
294 // Reset the document's scrollbars back to our defaults before we yield the floor.
295 m_firstLayout = true;
296 setScrollbarsSuppressed(true);
297 if (m_canHaveScrollbars)
298 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
300 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
301 setScrollbarsSuppressed(false);
304 void FrameView::resetScrollbarsAndClearContentsSize()
308 setScrollbarsSuppressed(true);
309 setContentsSize(IntSize());
310 setScrollbarsSuppressed(false);
313 void FrameView::init()
317 m_margins = LayoutSize(-1, -1); // undefined
318 m_size = LayoutSize();
320 // Propagate the marginwidth/height and scrolling modes to the view.
321 Element* ownerElement = frame().ownerElement();
322 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
323 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
324 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
325 setCanHaveScrollbars(false);
326 LayoutUnit marginWidth = frameElt->marginWidth();
327 LayoutUnit marginHeight = frameElt->marginHeight();
328 if (marginWidth != -1)
329 setMarginWidth(marginWidth);
330 if (marginHeight != -1)
331 setMarginHeight(marginHeight);
334 Page* page = frame().page();
335 if (page && page->chrome().client().shouldPaintEntireContents())
336 setPaintsEntireContents(true);
339 void FrameView::prepareForDetach()
341 detachCustomScrollbars();
342 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
343 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
344 removeFromAXObjectCache();
346 if (frame().page()) {
347 if (ScrollingCoordinator* scrollingCoordinator = frame().page()->scrollingCoordinator())
348 scrollingCoordinator->willDestroyScrollableArea(this);
352 void FrameView::detachCustomScrollbars()
354 Scrollbar* horizontalBar = horizontalScrollbar();
355 if (horizontalBar && horizontalBar->isCustomScrollbar())
356 setHasHorizontalScrollbar(false);
358 Scrollbar* verticalBar = verticalScrollbar();
359 if (verticalBar && verticalBar->isCustomScrollbar())
360 setHasVerticalScrollbar(false);
362 if (m_scrollCorner) {
363 m_scrollCorner->destroy();
368 void FrameView::recalculateScrollbarOverlayStyle()
370 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
371 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
373 Color backgroundColor = documentBackgroundColor();
374 if (backgroundColor.isValid()) {
375 // Reduce the background color from RGB to a lightness value
376 // and determine which scrollbar style to use based on a lightness
378 double hue, saturation, lightness;
379 backgroundColor.getHSL(hue, saturation, lightness);
380 if (lightness <= .5 && backgroundColor.alpha() > 0)
381 overlayStyle = ScrollbarOverlayStyleLight;
384 if (oldOverlayStyle != overlayStyle)
385 setScrollbarOverlayStyle(overlayStyle);
388 void FrameView::clear()
390 setCanBlitOnScroll(true);
394 setScrollbarsSuppressed(true);
397 bool FrameView::didFirstLayout() const
399 return !m_firstLayout;
402 void FrameView::invalidateRect(const IntRect& rect)
405 if (HostWindow* window = hostWindow())
406 window->invalidateContentsAndRootView(rect, false /*immediate*/);
410 RenderWidget* renderer = frame().ownerRenderer();
414 IntRect repaintRect = rect;
415 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
416 renderer->borderTop() + renderer->paddingTop());
417 renderer->repaintRectangle(repaintRect);
420 void FrameView::setFrameRect(const IntRect& newRect)
422 IntRect oldRect = frameRect();
423 if (newRect == oldRect)
426 #if ENABLE(TEXT_AUTOSIZING)
427 // Autosized font sizes depend on the width of the viewing area.
428 if (newRect.width() != oldRect.width()) {
429 Page* page = frame().page();
430 if (frame().isMainFrame() && page->settings().textAutosizingEnabled()) {
431 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext())
432 frame().document()->textAutosizer()->recalculateMultipliers();
437 ScrollView::setFrameRect(newRect);
439 updateScrollableAreaSet();
441 #if USE(ACCELERATED_COMPOSITING)
442 if (RenderView* renderView = this->renderView()) {
443 if (renderView->usesCompositing())
444 renderView->compositor().frameViewDidChangeSize();
448 if (!frameFlatteningEnabled())
449 sendResizeEventIfNeeded();
452 #if ENABLE(REQUEST_ANIMATION_FRAME)
453 bool FrameView::scheduleAnimation()
455 if (HostWindow* window = hostWindow()) {
456 window->scheduleAnimation();
463 void FrameView::setMarginWidth(LayoutUnit w)
465 // make it update the rendering area when set
466 m_margins.setWidth(w);
469 void FrameView::setMarginHeight(LayoutUnit h)
471 // make it update the rendering area when set
472 m_margins.setHeight(h);
475 bool FrameView::frameFlatteningEnabled() const
477 return frame().settings().frameFlatteningEnabled();
480 bool FrameView::isFrameFlatteningValidForThisFrame() const
482 if (!frameFlatteningEnabled())
485 HTMLFrameOwnerElement* owner = frame().ownerElement();
489 // Frame flattening is valid only for <frame> and <iframe>.
490 return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag);
493 bool FrameView::avoidScrollbarCreation() const
495 // with frame flattening no subframe can have scrollbars
496 // but we also cannot turn scrollbars off as we determine
497 // our flattening policy using that.
498 return isFrameFlatteningValidForThisFrame();
501 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
503 m_canHaveScrollbars = canHaveScrollbars;
504 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
507 void FrameView::updateCanHaveScrollbars()
511 scrollbarModes(hMode, vMode);
512 if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
513 setCanHaveScrollbars(false);
515 setCanHaveScrollbars(true);
518 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
520 if (!frame().settings().allowCustomScrollbarInMainFrame() && frame().isMainFrame())
521 return ScrollView::createScrollbar(orientation);
523 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
524 Document* doc = frame().document();
526 // Try the <body> element first as a scrollbar source.
527 Element* body = doc ? doc->body() : 0;
528 if (body && body->renderer() && body->renderer()->style().hasPseudoStyle(SCROLLBAR))
529 return RenderScrollbar::createCustomScrollbar(this, orientation, body);
531 // If the <body> didn't have a custom style, then the root element might.
532 Element* docElement = doc ? doc->documentElement() : 0;
533 if (docElement && docElement->renderer() && docElement->renderer()->style().hasPseudoStyle(SCROLLBAR))
534 return RenderScrollbar::createCustomScrollbar(this, orientation, docElement);
536 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
537 RenderWidget* frameRenderer = frame().ownerRenderer();
538 if (frameRenderer && frameRenderer->style().hasPseudoStyle(SCROLLBAR))
539 return RenderScrollbar::createCustomScrollbar(this, orientation, 0, &frame());
541 // Nobody set a custom style, so we just use a native scrollbar.
542 return ScrollView::createScrollbar(orientation);
545 void FrameView::setContentsSize(const IntSize& size)
547 if (size == contentsSize())
550 m_deferSetNeedsLayouts++;
552 ScrollView::setContentsSize(size);
553 ScrollView::contentsResized();
555 Page* page = frame().page();
559 updateScrollableAreaSet();
561 page->chrome().contentsSizeChanged(&frame(), size); // Notify only.
563 ASSERT(m_deferSetNeedsLayouts);
564 m_deferSetNeedsLayouts--;
566 if (!m_deferSetNeedsLayouts)
567 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
570 void FrameView::adjustViewSize()
572 RenderView* renderView = this->renderView();
576 ASSERT(frame().view() == this);
578 const IntRect rect = renderView->documentRect();
579 const IntSize& size = rect.size();
580 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !frame().document()->printing(), size == contentsSize());
582 setContentsSize(size);
585 void FrameView::applyOverflowToViewport(RenderElement* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
587 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
588 // overflow:hidden and overflow:scroll on <body> as applying to the document's
589 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
590 // use the root element.
592 // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when
593 // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a
596 bool overrideHidden = frame().isMainFrame() && ((frame().frameScaleFactor() > 1) || headerHeight() || footerHeight());
598 EOverflow overflowX = o->style().overflowX();
599 EOverflow overflowY = o->style().overflowY();
602 if (o->isSVGRoot()) {
603 // overflow is ignored in stand-alone SVG documents.
604 if (!toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument())
614 hMode = ScrollbarAuto;
616 hMode = ScrollbarAlwaysOff;
619 hMode = ScrollbarAlwaysOn;
622 hMode = ScrollbarAuto;
625 // Don't set it at all.
632 vMode = ScrollbarAuto;
634 vMode = ScrollbarAlwaysOff;
637 vMode = ScrollbarAlwaysOn;
640 vMode = ScrollbarAuto;
643 // Don't set it at all. Values of OPAGEDX and OPAGEDY are handled by applyPaginationToViewPort().
647 m_viewportRenderer = o;
650 void FrameView::applyPaginationToViewport()
652 Document* document = frame().document();
653 auto documentElement = document->documentElement();
654 RenderElement* documentRenderer = documentElement ? documentElement->renderer() : nullptr;
655 RenderElement* documentOrBodyRenderer = documentRenderer;
656 auto body = document->body();
657 if (body && body->renderer()) {
658 if (body->hasTagName(bodyTag))
659 documentOrBodyRenderer = documentRenderer->style().overflowX() == OVISIBLE && documentElement->hasTagName(htmlTag) ? body->renderer() : documentRenderer;
662 Pagination pagination;
664 if (!documentOrBodyRenderer) {
665 setPagination(pagination);
669 EOverflow overflowY = documentOrBodyRenderer->style().overflowY();
670 if (overflowY == OPAGEDX || overflowY == OPAGEDY) {
671 pagination.mode = WebCore::paginationModeForRenderStyle(documentOrBodyRenderer->style());
672 pagination.gap = static_cast<unsigned>(documentOrBodyRenderer->style().columnGap());
675 setPagination(pagination);
678 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
680 m_viewportRenderer = 0;
682 const HTMLFrameOwnerElement* owner = frame().ownerElement();
683 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
684 hMode = ScrollbarAlwaysOff;
685 vMode = ScrollbarAlwaysOff;
689 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
690 hMode = ScrollbarAuto;
691 // Seamless documents begin with heights of 0; we special case that here
692 // to correctly render documents that don't need scrollbars.
693 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size();
694 bool isSeamlessDocument = frame().document() && frame().document()->shouldDisplaySeamlesslyWithParent();
695 vMode = (isSeamlessDocument && !fullVisibleSize.height()) ? ScrollbarAlwaysOff : ScrollbarAuto;
697 hMode = ScrollbarAlwaysOff;
698 vMode = ScrollbarAlwaysOff;
702 Document* document = frame().document();
703 auto documentElement = document->documentElement();
704 RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr;
705 auto body = document->body();
706 if (body && body->renderer()) {
707 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
708 vMode = ScrollbarAlwaysOff;
709 hMode = ScrollbarAlwaysOff;
710 } else if (body->hasTagName(bodyTag)) {
711 // It's sufficient to just check the X overflow,
712 // since it's illegal to have visible in only one direction.
713 RenderElement* o = rootRenderer->style().overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
714 applyOverflowToViewport(o, hMode, vMode);
716 } else if (rootRenderer)
717 applyOverflowToViewport(rootRenderer, hMode, vMode);
721 #if USE(ACCELERATED_COMPOSITING)
722 void FrameView::updateCompositingLayersAfterStyleChange()
724 RenderView* renderView = this->renderView();
728 // If we expect to update compositing after an incipient layout, don't do so here.
729 if (inPreLayoutStyleUpdate() || layoutPending() || renderView->needsLayout())
732 RenderLayerCompositor& compositor = renderView->compositor();
733 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
734 compositor.cacheAcceleratedCompositingFlags();
735 compositor.updateCompositingLayers(CompositingUpdateAfterStyleChange);
738 void FrameView::updateCompositingLayersAfterLayout()
740 RenderView* renderView = this->renderView();
744 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
745 renderView->compositor().cacheAcceleratedCompositingFlags();
746 renderView->compositor().updateCompositingLayers(CompositingUpdateAfterLayout);
749 void FrameView::clearBackingStores()
751 RenderView* renderView = this->renderView();
755 RenderLayerCompositor& compositor = renderView->compositor();
756 ASSERT(compositor.inCompositingMode());
757 compositor.enableCompositingMode(false);
758 compositor.clearBackingForAllLayers();
761 void FrameView::restoreBackingStores()
763 RenderView* renderView = this->renderView();
767 RenderLayerCompositor& compositor = renderView->compositor();
768 compositor.enableCompositingMode(true);
769 compositor.updateCompositingLayers(CompositingUpdateAfterLayout);
772 bool FrameView::usesCompositedScrolling() const
774 RenderView* renderView = this->renderView();
777 if (frame().settings().compositedScrollingForFramesEnabled())
778 return renderView->compositor().inForcedCompositingMode();
782 GraphicsLayer* FrameView::layerForScrolling() const
784 RenderView* renderView = this->renderView();
787 return renderView->compositor().scrollLayer();
790 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
792 RenderView* renderView = this->renderView();
795 return renderView->compositor().layerForHorizontalScrollbar();
798 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
800 RenderView* renderView = this->renderView();
803 return renderView->compositor().layerForVerticalScrollbar();
806 GraphicsLayer* FrameView::layerForScrollCorner() const
808 RenderView* renderView = this->renderView();
811 return renderView->compositor().layerForScrollCorner();
814 TiledBacking* FrameView::tiledBacking()
816 RenderView* renderView = this->renderView();
820 RenderLayerBacking* backing = renderView->layer()->backing();
824 return backing->graphicsLayer()->tiledBacking();
827 uint64_t FrameView::scrollLayerID() const
829 RenderView* renderView = this->renderView();
833 RenderLayerBacking* backing = renderView->layer()->backing();
837 return backing->scrollLayerID();
840 #if ENABLE(RUBBER_BANDING)
841 GraphicsLayer* FrameView::layerForOverhangAreas() const
843 RenderView* renderView = this->renderView();
846 return renderView->compositor().layerForOverhangAreas();
849 GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const
851 RenderView* renderView = this->renderView();
855 return renderView->compositor().updateLayerForTopOverhangArea(wantsLayer);
858 GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const
860 RenderView* renderView = this->renderView();
864 return renderView->compositor().updateLayerForBottomOverhangArea(wantsLayer);
867 #endif // ENABLE(RUBBER_BANDING)
869 bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush)
871 RenderView* renderView = this->renderView();
873 return true; // We don't want to keep trying to update layers if we have no renderer.
875 ASSERT(frame().view() == this);
877 // If we sync compositing layers when a layout is pending, we may cause painting of compositing
878 // layer content to occur before layout has happened, which will cause paintContents() to bail.
882 // If we sync compositing layers and allow the repaint to be deferred, there is time for a
883 // visible flash to occur. Instead, stop the deferred repaint timer and repaint immediately.
884 flushDeferredRepaints();
886 renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame());
891 void FrameView::setNeedsOneShotDrawingSynchronization()
893 if (Page* page = frame().page())
894 page->chrome().client().setNeedsOneShotDrawingSynchronization();
897 #endif // USE(ACCELERATED_COMPOSITING)
899 void FrameView::setHeaderHeight(int headerHeight)
902 ASSERT(frame().isMainFrame());
903 m_headerHeight = headerHeight;
905 if (RenderView* renderView = this->renderView())
906 renderView->setNeedsLayout();
909 void FrameView::setFooterHeight(int footerHeight)
912 ASSERT(frame().isMainFrame());
913 m_footerHeight = footerHeight;
915 if (RenderView* renderView = this->renderView())
916 renderView->setNeedsLayout();
919 bool FrameView::hasCompositedContent() const
921 #if USE(ACCELERATED_COMPOSITING)
922 if (RenderView* renderView = this->renderView())
923 return renderView->compositor().inCompositingMode();
928 bool FrameView::hasCompositedContentIncludingDescendants() const
930 #if USE(ACCELERATED_COMPOSITING)
931 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
932 RenderView* renderView = frame->contentRenderer();
933 if (RenderLayerCompositor* compositor = renderView ? &renderView->compositor() : 0) {
934 if (compositor->inCompositingMode())
937 if (!RenderLayerCompositor::allowsIndependentlyCompositedFrames(this))
945 bool FrameView::hasCompositingAncestor() const
947 #if USE(ACCELERATED_COMPOSITING)
948 for (Frame* frame = this->frame().tree().parent(); frame; frame = frame->tree().parent()) {
949 if (FrameView* view = frame->view()) {
950 if (view->hasCompositedContent())
958 // Sometimes (for plug-ins) we need to eagerly go into compositing mode.
959 void FrameView::enterCompositingMode()
961 #if USE(ACCELERATED_COMPOSITING)
962 if (RenderView* renderView = this->renderView()) {
963 renderView->compositor().enableCompositingMode();
965 renderView->compositor().scheduleCompositingLayerUpdate();
970 bool FrameView::isEnclosedInCompositingLayer() const
972 #if USE(ACCELERATED_COMPOSITING)
973 auto frameOwnerRenderer = frame().ownerRenderer();
974 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
977 if (FrameView* parentView = parentFrameView())
978 return parentView->isEnclosedInCompositingLayer();
983 bool FrameView::flushCompositingStateIncludingSubframes()
985 #if USE(ACCELERATED_COMPOSITING)
986 bool allFramesFlushed = flushCompositingStateForThisFrame(&frame());
988 for (Frame* child = frame().tree().firstChild(); child; child = child->tree().traverseNext(&frame())) {
989 bool flushed = child->view()->flushCompositingStateForThisFrame(&frame());
990 allFramesFlushed &= flushed;
992 return allFramesFlushed;
993 #else // USE(ACCELERATED_COMPOSITING)
998 bool FrameView::isSoftwareRenderable() const
1000 #if USE(ACCELERATED_COMPOSITING)
1001 RenderView* renderView = this->renderView();
1002 return !renderView || !renderView->compositor().has3DContent();
1008 void FrameView::didMoveOnscreen()
1010 contentAreaDidShow();
1013 void FrameView::willMoveOffscreen()
1015 contentAreaDidHide();
1018 void FrameView::setIsInWindow(bool isInWindow)
1020 if (RenderView* renderView = this->renderView())
1021 renderView->setIsInWindow(isInWindow);
1024 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
1026 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
1029 inline void FrameView::forceLayoutParentViewIfNeeded()
1032 RenderWidget* ownerRenderer = frame().ownerRenderer();
1036 RenderBox* contentBox = embeddedContentBox();
1040 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
1041 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
1044 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
1045 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
1046 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
1047 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
1048 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
1049 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
1050 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
1051 Ref<FrameView> frameView(ownerRenderer->view().frameView());
1053 // Mark the owner renderer as needing layout.
1054 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
1056 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
1057 frameView->layout();
1061 void FrameView::layout(bool allowSubtree)
1066 // Many of the tasks performed during layout can cause this function to be re-entered,
1067 // so save the layout phase now and restore it on exit.
1068 TemporaryChange<LayoutPhase> layoutPhaseRestorer(m_layoutPhase, InPreLayout);
1070 // Protect the view from being deleted during layout (in recalcStyle)
1071 Ref<FrameView> protect(*this);
1073 // Every scroll that happens during layout is programmatic.
1074 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1076 bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening();
1078 if (inChildFrameLayoutWithFrameFlattening) {
1079 startLayoutAtMainFrameViewIfNeeded(allowSubtree);
1080 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
1081 if (!root->needsLayout())
1085 m_layoutTimer.stop();
1086 m_delayedLayout = false;
1087 m_setNeedsLayoutWasDeferred = false;
1089 // we shouldn't enter layout() while painting
1090 ASSERT(!isPainting());
1094 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(&frame());
1096 if (!allowSubtree && m_layoutRoot) {
1097 m_layoutRoot->markContainingBlocksForLayout(false);
1101 ASSERT(frame().view() == this);
1102 ASSERT(frame().document());
1104 Document& document = *frame().document();
1105 ASSERT(!document.inPageCache());
1108 RenderElement* root;
1111 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1113 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive() && !inChildFrameLayoutWithFrameFlattening) {
1114 // This is a new top-level layout. If there are any remaining tasks from the previous
1115 // layout, finish them now.
1116 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1117 performPostLayoutTasks();
1120 m_layoutPhase = InPreLayoutStyleUpdate;
1122 // Viewport-dependent media queries may cause us to need completely different style information.
1123 StyleResolver* styleResolver = document.styleResolverIfExists();
1124 if (!styleResolver || styleResolver->affectedByViewportChange()) {
1125 document.styleResolverChanged(DeferRecalcStyle);
1126 // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
1127 InspectorInstrumentation::mediaQueryResultChanged(&document);
1129 document.evaluateMediaQueryList();
1131 // If there is any pagination to apply, it will affect the RenderView's style, so we should
1132 // take care of that now.
1133 applyPaginationToViewport();
1135 // Always ensure our style info is up-to-date. This can happen in situations where
1136 // the layout beats any sort of style recalc update that needs to occur.
1137 document.updateStyleIfNeeded();
1138 m_layoutPhase = InPreLayout;
1140 subtree = m_layoutRoot;
1142 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
1143 // so there's no point to continuing to layout
1147 root = subtree ? m_layoutRoot : document.renderView();
1149 // FIXME: Do we need to set m_size here?
1153 // Close block here so we can set up the font cache purge preventer, which we will still
1154 // want in scope even after we want m_layoutSchedulingEnabled to be restored again.
1155 // The next block sets m_layoutSchedulingEnabled back to false once again.
1158 FontCachePurgePreventer fontCachePurgePreventer;
1161 ++m_nestedLayoutCount;
1164 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
1166 if (!m_layoutRoot) {
1167 HTMLElement* body = document.body();
1168 if (body && body->renderer()) {
1169 if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) {
1170 body->renderer()->setChildNeedsLayout();
1171 } else if (body->hasTagName(bodyTag)) {
1172 if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox()->stretchesToViewport())
1173 body->renderer()->setChildNeedsLayout();
1177 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1178 if (m_firstLayout && !frame().ownerElement())
1179 printf("Elapsed time before first layout: %d\n", document.elapsedTime());
1183 autoSizeIfEnabled();
1185 m_needsFullRepaint = !subtree && (m_firstLayout || toRenderView(*root).printing());
1188 ScrollbarMode hMode;
1189 ScrollbarMode vMode;
1190 calculateScrollbarModesForLayout(hMode, vMode);
1192 if (m_firstLayout || (hMode != horizontalScrollbarMode() || vMode != verticalScrollbarMode())) {
1193 if (m_firstLayout) {
1194 setScrollbarsSuppressed(true);
1196 m_firstLayout = false;
1197 m_firstLayoutCallbackPending = true;
1198 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
1199 m_lastViewportSize = fixedLayoutSize();
1201 m_lastViewportSize = visibleContentRect(IncludeScrollbars).size();
1203 m_lastZoomFactor = root->style().zoom();
1205 // Set the initial vMode to AlwaysOn if we're auto.
1206 if (vMode == ScrollbarAuto)
1207 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
1208 // Set the initial hMode to AlwaysOff if we're auto.
1209 if (hMode == ScrollbarAuto)
1210 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
1212 setScrollbarModes(hMode, vMode);
1213 setScrollbarsSuppressed(false, true);
1215 setScrollbarModes(hMode, vMode);
1218 LayoutSize oldSize = m_size;
1220 m_size = layoutSize();
1222 if (oldSize != m_size) {
1223 m_needsFullRepaint = true;
1224 if (!m_firstLayout) {
1225 RenderBox* rootRenderer = document.documentElement() ? document.documentElement()->renderBox() : 0;
1226 RenderBox* bodyRenderer = rootRenderer && document.body() ? document.body()->renderBox() : 0;
1227 if (bodyRenderer && bodyRenderer->stretchesToViewport())
1228 bodyRenderer->setChildNeedsLayout();
1229 else if (rootRenderer && rootRenderer->stretchesToViewport())
1230 rootRenderer->setChildNeedsLayout();
1234 m_layoutPhase = InPreLayout;
1237 layer = root->enclosingLayer();
1239 bool disableLayoutState = false;
1241 disableLayoutState = root->view().shouldDisableLayoutStateForSubtree(root);
1242 root->view().pushLayoutState(*root);
1244 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? &root->view() : 0);
1246 ASSERT(m_layoutPhase == InPreLayout);
1247 m_layoutPhase = InLayout;
1249 beginDeferredRepaints();
1250 forceLayoutParentViewIfNeeded();
1252 ASSERT(m_layoutPhase == InLayout);
1255 #if ENABLE(IOS_TEXT_AUTOSIZING)
1256 float minZoomFontSize = frame().settings().minimumZoomFontSize();
1257 float visWidth = frame().page()->mainFrame().textAutosizingWidth();
1258 if (minZoomFontSize && visWidth && !root->view().printing()) {
1259 root->adjustComputedFontSizesOnBlocks(minZoomFontSize, visWidth);
1260 bool needsLayout = root->needsLayout();
1265 #if ENABLE(TEXT_AUTOSIZING)
1266 if (document.textAutosizer()->processSubtree(root) && root->needsLayout())
1269 endDeferredRepaints();
1271 ASSERT(m_layoutPhase == InLayout);
1274 root->view().popLayoutState(*root);
1278 // Close block here to end the scope of changeSchedulingEnabled and layoutStateDisabler.
1281 m_layoutPhase = InViewSizeAdjust;
1283 bool neededFullRepaint = m_needsFullRepaint;
1285 if (!subtree && !toRenderView(*root).printing())
1288 m_layoutPhase = InPostLayout;
1290 m_needsFullRepaint = neededFullRepaint;
1292 // Now update the positions of all layers.
1293 beginDeferredRepaints();
1294 if (m_needsFullRepaint)
1295 root->view().repaintRootContents();
1297 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_needsFullRepaint));
1299 endDeferredRepaints();
1301 #if USE(ACCELERATED_COMPOSITING)
1302 updateCompositingLayersAfterLayout();
1307 #if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL)
1308 if (AXObjectCache* cache = root->document().existingAXObjectCache())
1309 cache->postNotification(root, AXObjectCache::AXLayoutComplete);
1312 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
1313 updateAnnotatedRegions();
1316 ASSERT(!root->needsLayout());
1318 updateCanBlitOnScrollRecursively();
1320 if (document.hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1321 updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
1323 if (!m_postLayoutTasksTimer.isActive()) {
1324 if (!m_inSynchronousPostLayout) {
1325 if (inChildFrameLayoutWithFrameFlattening)
1326 updateWidgetPositions();
1328 TemporaryChange<bool> inSynchronousPostLayoutChange(m_inSynchronousPostLayout, true);
1329 performPostLayoutTasks(); // Calls resumeScheduledEvents().
1333 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout || inChildFrameLayoutWithFrameFlattening)) {
1334 // If we need layout or are already in a synchronous call to postLayoutTasks(),
1335 // defer widget updates and event dispatch until after we return. postLayoutTasks()
1336 // can make us need to update again, and we can get stuck in a nasty cycle unless
1337 // we call it through the timer here.
1338 m_postLayoutTasksTimer.startOneShot(0);
1344 InspectorInstrumentation::didLayout(cookie, root);
1346 --m_nestedLayoutCount;
1348 if (m_nestedLayoutCount)
1351 if (Page* page = frame().page())
1352 page->chrome().client().layoutUpdated(&frame());
1355 RenderBox* FrameView::embeddedContentBox() const
1358 RenderView* renderView = this->renderView();
1362 RenderObject* firstChild = renderView->firstChild();
1363 if (!firstChild || !firstChild->isBox())
1366 // Curently only embedded SVG documents participate in the size-negotiation logic.
1367 if (toRenderBox(firstChild)->isSVGRoot())
1368 return toRenderBox(firstChild);
1374 void FrameView::addEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1376 if (!m_embeddedObjectsToUpdate)
1377 m_embeddedObjectsToUpdate = adoptPtr(new ListHashSet<RenderEmbeddedObject*>);
1379 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
1380 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
1381 // Tell the DOM element that it needs a widget update.
1382 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
1383 if (!pluginElement.needsCheckForSizeChange())
1384 pluginElement.setNeedsWidgetUpdate(true);
1387 m_embeddedObjectsToUpdate->add(&embeddedObject);
1390 void FrameView::removeEmbeddedObjectToUpdate(RenderEmbeddedObject& embeddedObject)
1392 if (!m_embeddedObjectsToUpdate)
1395 m_embeddedObjectsToUpdate->remove(&embeddedObject);
1398 void FrameView::setMediaType(const String& mediaType)
1400 m_mediaType = mediaType;
1403 String FrameView::mediaType() const
1405 // See if we have an override type.
1406 String overrideType = frame().loader().client().overrideMediaType();
1407 InspectorInstrumentation::applyEmulatedMedia(&frame(), &overrideType);
1408 if (!overrideType.isNull())
1409 return overrideType;
1413 void FrameView::adjustMediaTypeForPrinting(bool printing)
1416 if (m_mediaTypeWhenNotPrinting.isNull())
1417 m_mediaTypeWhenNotPrinting = mediaType();
1418 setMediaType("print");
1420 if (!m_mediaTypeWhenNotPrinting.isNull())
1421 setMediaType(m_mediaTypeWhenNotPrinting);
1422 m_mediaTypeWhenNotPrinting = String();
1426 bool FrameView::useSlowRepaints(bool considerOverlap) const
1428 bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects());
1430 // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints ==
1431 // m_contentIsOpaque, so don't take the fast path for composited layers
1432 // if they are a platform widget in order to get painting correctness
1433 // for transparent layers. See the comment in WidgetMac::paint.
1434 if (contentsInCompositedLayer() && !platformWidget())
1437 bool isOverlapped = m_isOverlapped && considerOverlap;
1439 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1442 if (FrameView* parentView = parentFrameView())
1443 return parentView->useSlowRepaints(considerOverlap);
1448 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1450 return useSlowRepaints(false);
1453 void FrameView::updateCanBlitOnScrollRecursively()
1455 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1456 if (FrameView* view = frame->view())
1457 view->setCanBlitOnScroll(!view->useSlowRepaints());
1461 bool FrameView::contentsInCompositedLayer() const
1463 #if USE(ACCELERATED_COMPOSITING)
1464 RenderView* renderView = this->renderView();
1465 if (renderView && renderView->isComposited()) {
1466 GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer();
1467 if (layer && layer->drawsContent())
1474 void FrameView::setCannotBlitToWindow()
1476 m_cannotBlitToWindow = true;
1477 updateCanBlitOnScrollRecursively();
1480 void FrameView::addSlowRepaintObject(RenderElement* o)
1482 bool hadSlowRepaintObjects = hasSlowRepaintObjects();
1484 if (!m_slowRepaintObjects)
1485 m_slowRepaintObjects = adoptPtr(new HashSet<RenderElement*>);
1487 m_slowRepaintObjects->add(o);
1489 if (!hadSlowRepaintObjects) {
1490 updateCanBlitOnScrollRecursively();
1492 if (Page* page = frame().page()) {
1493 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1494 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1499 void FrameView::removeSlowRepaintObject(RenderElement* o)
1501 if (!m_slowRepaintObjects)
1504 m_slowRepaintObjects->remove(o);
1505 if (m_slowRepaintObjects->isEmpty()) {
1506 m_slowRepaintObjects = nullptr;
1507 updateCanBlitOnScrollRecursively();
1509 if (Page* page = frame().page()) {
1510 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1511 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1516 void FrameView::addViewportConstrainedObject(RenderElement* object)
1518 if (!m_viewportConstrainedObjects)
1519 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1521 if (!m_viewportConstrainedObjects->contains(object)) {
1522 m_viewportConstrainedObjects->add(object);
1523 if (platformWidget())
1524 updateCanBlitOnScrollRecursively();
1526 if (Page* page = frame().page()) {
1527 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1528 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1533 void FrameView::removeViewportConstrainedObject(RenderElement* object)
1535 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->remove(object)) {
1536 if (Page* page = frame().page()) {
1537 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1538 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1541 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1542 // why isn't the same check being made here?
1543 updateCanBlitOnScrollRecursively();
1547 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1549 LayoutRect viewportRect = visibleContentRect();
1550 viewportRect.setLocation(toPoint(scrollOffsetForFixedPosition()));
1551 return viewportRect;
1554 IntSize FrameView::scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& totalContentsSize, const IntPoint& scrollPosition, const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements behaviorForFixed, int headerHeight, int footerHeight)
1557 if (behaviorForFixed == StickToDocumentBounds)
1558 position = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight);
1560 position = scrollPosition;
1561 position.setY(position.y() - headerHeight);
1564 IntSize maxSize = totalContentsSize - visibleContentRect.size();
1566 float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width();
1567 float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height();
1569 return IntSize(position.x() * dragFactorX / frameScaleFactor, position.y() * dragFactorY / frameScaleFactor);
1572 IntSize FrameView::scrollOffsetForFixedPosition() const
1574 IntRect visibleContentRect = this->visibleContentRect();
1575 IntSize totalContentsSize = this->totalContentsSize();
1576 IntPoint scrollPosition = this->scrollPosition();
1577 IntPoint scrollOrigin = this->scrollOrigin();
1578 float frameScaleFactor = frame().frameScaleFactor();
1579 ScrollBehaviorForFixedElements behaviorForFixed = scrollBehaviorForFixedElements();
1580 return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), behaviorForFixed, headerHeight(), footerHeight());
1583 IntPoint FrameView::minimumScrollPosition() const
1585 IntPoint minimumPosition(ScrollView::minimumScrollPosition());
1587 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToBottom)
1588 minimumPosition.setY(maximumScrollPosition().y());
1590 return minimumPosition;
1593 IntPoint FrameView::maximumScrollPosition() const
1595 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y());
1597 maximumOffset.clampNegativeToZero();
1599 if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
1600 maximumOffset.setY(minimumScrollPosition().y());
1602 return maximumOffset;
1605 bool FrameView::fixedElementsLayoutRelativeToFrame() const
1607 return frame().settings().fixedElementsLayoutRelativeToFrame();
1610 IntPoint FrameView::lastKnownMousePosition() const
1612 return frame().eventHandler().lastKnownMousePosition();
1615 bool FrameView::isHandlingWheelEvent() const
1617 return frame().eventHandler().isHandlingWheelEvent();
1620 bool FrameView::shouldSetCursor() const
1622 Page* page = frame().page();
1623 return page && page->isOnscreen() && page->focusController().isActive();
1626 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1628 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1629 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1633 const bool isCompositedContentLayer = contentsInCompositedLayer();
1635 // Get the rects of the fixed objects visible in the rectToScroll
1636 Region regionToUpdate;
1637 for (auto& renderer : *m_viewportConstrainedObjects) {
1638 if (!renderer->style().hasViewportConstrainedPosition())
1640 #if USE(ACCELERATED_COMPOSITING)
1641 if (renderer->isComposited())
1645 // Fixed items should always have layers.
1646 ASSERT(renderer->hasLayer());
1647 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1649 #if USE(ACCELERATED_COMPOSITING)
1650 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1651 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1652 // Don't invalidate for invisible fixed layers.
1657 #if ENABLE(CSS_FILTERS)
1658 if (layer->hasAncestorWithFilterOutsets()) {
1659 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1660 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1664 IntRect updateRect = pixelSnappedIntRect(layer->repaintRectIncludingNonCompositingDescendants());
1665 updateRect = contentsToRootView(updateRect);
1666 if (!isCompositedContentLayer && clipsRepaints())
1667 updateRect.intersect(rectToScroll);
1668 if (!updateRect.isEmpty())
1669 regionToUpdate.unite(updateRect);
1673 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1675 // 2) update the area of fixed objects that has been invalidated
1676 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1677 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1678 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1679 IntRect updateRect = subRectsToUpdate[i];
1680 IntRect scrolledRect = updateRect;
1681 scrolledRect.move(scrollDelta);
1682 updateRect.unite(scrolledRect);
1683 #if USE(ACCELERATED_COMPOSITING)
1684 if (isCompositedContentLayer) {
1685 updateRect = rootViewToContents(updateRect);
1686 ASSERT(renderView());
1687 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1691 if (clipsRepaints())
1692 updateRect.intersect(rectToScroll);
1693 hostWindow()->invalidateContentsAndRootView(updateRect, false);
1699 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1701 #if USE(ACCELERATED_COMPOSITING)
1702 if (contentsInCompositedLayer()) {
1703 IntRect updateRect = visibleContentRect();
1705 // Make sure to "apply" the scale factor here since we're converting from frame view
1706 // coordinates to layer backing coordinates.
1707 updateRect.scale(1 / frame().frameScaleFactor());
1709 ASSERT(renderView());
1710 renderView()->layer()->setBackingNeedsRepaintInRect(updateRect);
1713 repaintSlowRepaintObjects();
1715 if (RenderWidget* frameRenderer = frame().ownerRenderer()) {
1716 if (isEnclosedInCompositingLayer()) {
1717 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1718 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1719 visibleWidth(), visibleHeight());
1720 frameRenderer->repaintRectangle(rect);
1726 ScrollView::scrollContentsSlowPath(updateRect);
1729 void FrameView::repaintSlowRepaintObjects()
1731 if (!m_slowRepaintObjects)
1734 // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly
1735 // repaint them after scrolling.
1736 for (auto& renderer : *m_slowRepaintObjects)
1737 renderer->repaint();
1740 // Note that this gets called at painting time.
1741 void FrameView::setIsOverlapped(bool isOverlapped)
1743 if (isOverlapped == m_isOverlapped)
1746 m_isOverlapped = isOverlapped;
1747 updateCanBlitOnScrollRecursively();
1749 #if USE(ACCELERATED_COMPOSITING)
1750 if (hasCompositedContentIncludingDescendants()) {
1751 // Overlap can affect compositing tests, so if it changes, we need to trigger
1752 // a layer update in the parent document.
1753 if (Frame* parentFrame = frame().tree().parent()) {
1754 if (RenderView* parentView = parentFrame->contentRenderer()) {
1755 RenderLayerCompositor& compositor = parentView->compositor();
1756 compositor.setCompositingLayersNeedRebuild();
1757 compositor.scheduleCompositingLayerUpdate();
1761 if (RenderLayerCompositor::allowsIndependentlyCompositedFrames(this)) {
1762 // We also need to trigger reevaluation for this and all descendant frames,
1763 // since a frame uses compositing if any ancestor is compositing.
1764 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1765 if (RenderView* view = frame->contentRenderer()) {
1766 RenderLayerCompositor& compositor = view->compositor();
1767 compositor.setCompositingLayersNeedRebuild();
1768 compositor.scheduleCompositingLayerUpdate();
1776 bool FrameView::isOverlappedIncludingAncestors() const
1781 if (FrameView* parentView = parentFrameView()) {
1782 if (parentView->isOverlapped())
1789 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1791 if (contentIsOpaque == m_contentIsOpaque)
1794 m_contentIsOpaque = contentIsOpaque;
1795 updateCanBlitOnScrollRecursively();
1798 void FrameView::restoreScrollbar()
1800 setScrollbarsSuppressed(false);
1803 bool FrameView::scrollToFragment(const URL& url)
1805 // If our URL has no ref, then we have no place we need to jump to.
1806 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1807 // and possibly repaint because :target pseudo class may have been
1808 // set (see bug 11321).
1809 if (!url.hasFragmentIdentifier() && !frame().document()->cssTarget())
1812 String fragmentIdentifier = url.fragmentIdentifier();
1813 if (scrollToAnchor(fragmentIdentifier))
1816 // Try again after decoding the ref, based on the document's encoding.
1817 if (TextResourceDecoder* decoder = frame().document()->decoder())
1818 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
1823 bool FrameView::scrollToAnchor(const String& name)
1825 ASSERT(frame().document());
1827 if (!frame().document()->haveStylesheetsLoaded()) {
1828 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1832 frame().document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1834 Element* anchorElement = frame().document()->findAnchor(name);
1836 // Setting to null will clear the current target.
1837 frame().document()->setCSSTarget(anchorElement);
1840 if (frame().document()->isSVGDocument()) {
1841 if (SVGSVGElement* svg = toSVGDocument(frame().document())->rootElement()) {
1842 svg->setupInitialView(name, anchorElement);
1849 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1850 if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1853 maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : frame().document());
1855 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1856 if (anchorElement && anchorElement->isFocusable())
1857 frame().document()->setFocusedElement(anchorElement);
1862 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1864 m_maintainScrollPositionAnchor = anchorNode;
1865 if (!m_maintainScrollPositionAnchor)
1868 // We need to update the layout before scrolling, otherwise we could
1869 // really mess things up if an anchor scroll comes at a bad moment.
1870 frame().document()->updateStyleIfNeeded();
1871 // Only do a layout if changes have occurred that make it necessary.
1872 RenderView* renderView = this->renderView();
1873 if (renderView && renderView->needsLayout())
1879 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1881 frame().document()->updateLayoutIgnorePendingStylesheets();
1883 LayoutRect bounds = element->boundingBox();
1884 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
1885 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
1886 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
1889 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1891 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1892 m_maintainScrollPositionAnchor = 0;
1893 ScrollView::setScrollPosition(scrollPoint);
1896 void FrameView::delegatesScrollingDidChange()
1898 #if USE(ACCELERATED_COMPOSITING)
1899 // When we switch to delgatesScrolling mode, we should destroy the scrolling/clipping layers in RenderLayerCompositor.
1900 if (hasCompositedContent())
1901 clearBackingStores();
1905 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
1907 bool visibleContentSizeDidChange = false;
1908 if (visibleContentRect.size() != this->fixedVisibleContentRect().size()) {
1909 // When the viewport size changes or the content is scaled, we need to
1910 // reposition the fixed and sticky positioned elements.
1911 setViewportConstrainedObjectsNeedLayout();
1912 visibleContentSizeDidChange = true;
1915 IntSize offset = scrollOffset();
1916 ScrollView::setFixedVisibleContentRect(visibleContentRect);
1917 if (offset != scrollOffset()) {
1918 updateLayerPositionsAfterScrolling();
1919 if (frame().page()->settings().acceleratedCompositingForFixedPositionEnabled())
1920 updateCompositingLayersAfterScrolling();
1921 scrollAnimator()->setCurrentPosition(scrollPosition());
1922 scrollPositionChanged();
1924 if (visibleContentSizeDidChange) {
1925 // Update the scroll-bars to calculate new page-step size.
1926 updateScrollbars(scrollOffset());
1928 frame().loader().client().didChangeScrollOffset();
1931 void FrameView::setViewportConstrainedObjectsNeedLayout()
1933 if (!hasViewportConstrainedObjects())
1936 for (auto& renderer : *m_viewportConstrainedObjects)
1937 renderer->setNeedsLayout();
1940 void FrameView::scrollPositionChangedViaPlatformWidget()
1942 updateLayerPositionsAfterScrolling();
1943 updateCompositingLayersAfterScrolling();
1944 repaintSlowRepaintObjects();
1945 scrollPositionChanged();
1948 void FrameView::scrollPositionChanged()
1950 frame().eventHandler().sendScrollEvent();
1951 frame().eventHandler().dispatchFakeMouseMoveEventSoon();
1953 #if USE(ACCELERATED_COMPOSITING)
1954 if (RenderView* renderView = this->renderView()) {
1955 if (renderView->usesCompositing())
1956 renderView->compositor().frameViewDidScroll();
1961 void FrameView::updateLayerPositionsAfterScrolling()
1963 // If we're scrolling as a result of updating the view size after layout, we'll update widgets and layer positions soon anyway.
1964 if (m_layoutPhase == InViewSizeAdjust)
1967 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
1968 if (RenderView* renderView = this->renderView()) {
1969 updateWidgetPositions();
1970 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
1975 bool FrameView::shouldUpdateCompositingLayersAfterScrolling() const
1977 #if ENABLE(THREADED_SCROLLING)
1978 // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
1980 Page* page = frame().page();
1984 if (&page->mainFrame() != &frame())
1987 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
1988 if (!scrollingCoordinator)
1991 if (!scrollingCoordinator->supportsFixedPositionLayers())
1994 if (scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread())
1997 if (inProgrammaticScroll())
2005 void FrameView::updateCompositingLayersAfterScrolling()
2007 #if USE(ACCELERATED_COMPOSITING)
2008 if (!shouldUpdateCompositingLayersAfterScrolling())
2011 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
2012 if (RenderView* renderView = this->renderView())
2013 renderView->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
2018 bool FrameView::isRubberBandInProgress() const
2020 if (scrollbarsSuppressed())
2023 // If the scrolling thread updates the scroll position for this FrameView, then we should return
2024 // ScrollingCoordinator::isRubberBandInProgress().
2025 if (Page* page = frame().page()) {
2026 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
2027 if (!scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread())
2028 return scrollingCoordinator->isRubberBandInProgress();
2032 // If the main thread updates the scroll position for this FrameView, we should return
2033 // ScrollAnimator::isRubberBandInProgress().
2034 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
2035 return scrollAnimator->isRubberBandInProgress();
2040 bool FrameView::requestScrollPositionUpdate(const IntPoint& position)
2042 #if ENABLE(THREADED_SCROLLING)
2043 if (TiledBacking* tiledBacking = this->tiledBacking()) {
2044 IntRect visibleRect = visibleContentRect();
2045 visibleRect.setLocation(position);
2046 tiledBacking->prepopulateRect(visibleRect);
2049 if (Page* page = frame().page()) {
2050 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2051 return scrollingCoordinator->requestScrollPositionUpdate(this, position);
2054 UNUSED_PARAM(position);
2060 HostWindow* FrameView::hostWindow() const
2062 if (Page* page = frame().page())
2063 return &page->chrome();
2067 void FrameView::addTrackedRepaintRect(const IntRect& r)
2069 if (!m_isTrackingRepaints || r.isEmpty())
2072 IntRect repaintRect = r;
2073 repaintRect.move(-scrollOffset());
2074 m_trackedRepaintRects.append(repaintRect);
2077 const unsigned cRepaintRectUnionThreshold = 25;
2079 void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
2081 ASSERT(!frame().ownerElement());
2083 addTrackedRepaintRect(r);
2085 double delay = m_deferringRepaints ? 0 : adjustedDeferredRepaintDelay();
2086 if ((m_deferringRepaints || m_deferredRepaintTimer.isActive() || delay) && !immediate) {
2087 IntRect paintRect = r;
2088 if (clipsRepaints() && !paintsEntireContents())
2089 paintRect.intersect(visibleContentRect());
2090 if (paintRect.isEmpty())
2092 if (m_repaintCount == cRepaintRectUnionThreshold) {
2093 IntRect unionedRect;
2094 for (unsigned i = 0; i < cRepaintRectUnionThreshold; ++i)
2095 unionedRect.unite(pixelSnappedIntRect(m_repaintRects[i]));
2096 m_repaintRects.clear();
2097 m_repaintRects.append(unionedRect);
2099 if (m_repaintCount < cRepaintRectUnionThreshold)
2100 m_repaintRects.append(paintRect);
2102 m_repaintRects[0].unite(paintRect);
2105 if (!m_deferringRepaints)
2106 startDeferredRepaintTimer(delay);
2111 if (!shouldUpdate(immediate))
2114 #if USE(TILED_BACKING_STORE)
2115 if (frame().tiledBackingStore()) {
2116 frame().tiledBackingStore()->invalidate(r);
2120 ScrollView::repaintContentRectangle(r, immediate);
2123 void FrameView::contentsResized()
2125 ScrollView::contentsResized();
2129 void FrameView::fixedLayoutSizeChanged()
2131 // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized().
2132 // An ASSERT is triggered when a view schedules a layout before being attached to a frame.
2133 if (!frame().view())
2135 ScrollView::fixedLayoutSizeChanged();
2138 void FrameView::visibleContentsResized()
2140 // We check to make sure the view is attached to a frame() as this method can
2141 // be triggered before the view is attached by Frame::createView(...) setting
2142 // various values such as setScrollBarModes(...) for example. An ASSERT is
2143 // triggered when a view is layout before being attached to a frame().
2144 if (!frame().view())
2147 if (!useFixedLayout() && needsLayout())
2150 #if USE(ACCELERATED_COMPOSITING)
2151 if (RenderView* renderView = this->renderView()) {
2152 if (renderView->usesCompositing())
2153 renderView->compositor().frameViewDidChangeSize();
2158 void FrameView::addedOrRemovedScrollbar()
2160 #if USE(ACCELERATED_COMPOSITING)
2161 if (RenderView* renderView = this->renderView()) {
2162 if (renderView->usesCompositing())
2163 renderView->compositor().frameViewDidAddOrRemoveScrollbars();
2168 void FrameView::beginDeferredRepaints()
2170 if (!frame().isMainFrame()) {
2171 frame().mainFrame().view()->beginDeferredRepaints();
2175 m_deferringRepaints++;
2178 void FrameView::endDeferredRepaints()
2180 if (!frame().isMainFrame()) {
2181 frame().mainFrame().view()->endDeferredRepaints();
2185 ASSERT(m_deferringRepaints > 0);
2187 if (--m_deferringRepaints)
2190 if (m_deferredRepaintTimer.isActive())
2193 if (double delay = adjustedDeferredRepaintDelay()) {
2194 startDeferredRepaintTimer(delay);
2198 doDeferredRepaints();
2201 void FrameView::startDeferredRepaintTimer(double delay)
2203 if (m_deferredRepaintTimer.isActive())
2206 m_deferredRepaintTimer.startOneShot(delay);
2209 void FrameView::handleLoadCompleted()
2211 // Once loading has completed, allow autoSize one last opportunity to
2212 // reduce the size of the frame.
2213 autoSizeIfEnabled();
2214 if (shouldUseLoadTimeDeferredRepaintDelay())
2216 m_deferredRepaintDelay = s_normalDeferredRepaintDelay;
2217 flushDeferredRepaints();
2220 void FrameView::flushDeferredRepaints()
2222 if (!m_deferredRepaintTimer.isActive())
2224 m_deferredRepaintTimer.stop();
2225 doDeferredRepaints();
2228 void FrameView::doDeferredRepaints()
2230 ASSERT(!m_deferringRepaints);
2231 if (!shouldUpdate()) {
2232 m_repaintRects.clear();
2236 unsigned size = m_repaintRects.size();
2237 for (unsigned i = 0; i < size; i++) {
2238 #if USE(TILED_BACKING_STORE)
2239 if (frame().tiledBackingStore()) {
2240 frame().tiledBackingStore()->invalidate(pixelSnappedIntRect(m_repaintRects[i]));
2244 ScrollView::repaintContentRectangle(pixelSnappedIntRect(m_repaintRects[i]), false);
2246 m_repaintRects.clear();
2249 updateDeferredRepaintDelayAfterRepaint();
2252 bool FrameView::shouldUseLoadTimeDeferredRepaintDelay() const
2254 // Don't defer after the initial load of the page has been completed.
2255 if (frame().tree().top().loader().isComplete())
2257 Document* document = frame().document();
2260 if (document->parsing())
2262 if (document->cachedResourceLoader()->requestCount())
2267 void FrameView::updateDeferredRepaintDelayAfterRepaint()
2269 if (!shouldUseLoadTimeDeferredRepaintDelay()) {
2270 m_deferredRepaintDelay = s_normalDeferredRepaintDelay;
2273 double incrementedRepaintDelay = m_deferredRepaintDelay + s_deferredRepaintDelayIncrementDuringLoading;
2274 m_deferredRepaintDelay = std::min(incrementedRepaintDelay, s_maxDeferredRepaintDelayDuringLoading);
2277 void FrameView::resetDeferredRepaintDelay()
2279 m_deferredRepaintDelay = 0;
2280 if (m_deferredRepaintTimer.isActive()) {
2281 m_deferredRepaintTimer.stop();
2282 if (!m_deferringRepaints)
2283 doDeferredRepaints();
2285 #if USE(ACCELERATED_COMPOSITING)
2286 if (RenderView* view = renderView())
2287 view->compositor().disableLayerFlushThrottlingTemporarilyForInteraction();
2291 double FrameView::adjustedDeferredRepaintDelay() const
2293 ASSERT(!m_deferringRepaints);
2294 if (!m_deferredRepaintDelay)
2296 double timeSinceLastPaint = monotonicallyIncreasingTime() - m_lastPaintTime;
2297 return std::max<double>(0, m_deferredRepaintDelay - timeSinceLastPaint);
2300 void FrameView::deferredRepaintTimerFired(Timer<FrameView>*)
2302 doDeferredRepaints();
2305 void FrameView::updateLayerFlushThrottlingInAllFrames()
2307 #if USE(ACCELERATED_COMPOSITING)
2308 bool isMainLoadProgressing = frame().page()->progress().isMainLoadProgressing();
2309 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2310 if (RenderView* renderView = frame->contentRenderer())
2311 renderView->compositor().setLayerFlushThrottlingEnabled(isMainLoadProgressing);
2316 void FrameView::adjustTiledBackingCoverage()
2318 #if USE(ACCELERATED_COMPOSITING)
2319 RenderView* renderView = this->renderView();
2320 if (renderView && renderView->layer()->backing())
2321 renderView->layer()->backing()->adjustTiledBackingCoverage();
2325 void FrameView::layoutTimerFired(Timer<FrameView>*)
2327 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2328 if (!frame().document()->ownerElement())
2329 printf("Layout timer fired at %d\n", frame().document()->elapsedTime());
2334 void FrameView::scheduleRelayout()
2336 // FIXME: We should assert the page is not in the page cache, but that is causing
2337 // too many false assertions. See <rdar://problem/7218118>.
2338 ASSERT(frame().view() == this);
2341 m_layoutRoot->markContainingBlocksForLayout(false);
2344 if (!m_layoutSchedulingEnabled)
2348 if (!frame().document()->shouldScheduleLayout())
2350 InspectorInstrumentation::didInvalidateLayout(&frame());
2351 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
2352 // Also invalidate parent frame starting from the owner element of this frame.
2353 if (frame().ownerRenderer() && isInChildFrameWithFrameFlattening())
2354 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
2356 int delay = frame().document()->minimumLayoutDelay();
2357 if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
2358 unscheduleRelayout();
2359 if (m_layoutTimer.isActive())
2362 m_delayedLayout = delay != 0;
2364 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2365 if (!frame().document()->ownerElement())
2366 printf("Scheduling layout for %d\n", delay);
2369 m_layoutTimer.startOneShot(delay * 0.001);
2372 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
2374 for (RenderObject* r = descendant; r; r = r->container()) {
2381 void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot)
2383 ASSERT(renderView());
2384 RenderView& renderView = *this->renderView();
2386 // Try to catch unnecessary work during render tree teardown.
2387 ASSERT(!renderView.documentBeingDestroyed());
2388 ASSERT(frame().view() == this);
2390 if (renderView.needsLayout()) {
2391 newRelayoutRoot.markContainingBlocksForLayout(false);
2395 if (!layoutPending() && m_layoutSchedulingEnabled) {
2396 int delay = renderView.document().minimumLayoutDelay();
2397 ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout());
2398 m_layoutRoot = &newRelayoutRoot;
2399 InspectorInstrumentation::didInvalidateLayout(&frame());
2400 m_delayedLayout = delay != 0;
2401 m_layoutTimer.startOneShot(delay * 0.001);
2405 if (m_layoutRoot == &newRelayoutRoot)
2408 if (!m_layoutRoot) {
2409 // Just relayout the subtree.
2410 newRelayoutRoot.markContainingBlocksForLayout(false);
2411 InspectorInstrumentation::didInvalidateLayout(&frame());
2415 if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) {
2416 // Keep the current root.
2417 newRelayoutRoot.markContainingBlocksForLayout(false, m_layoutRoot);
2418 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2422 if (isObjectAncestorContainerOf(&newRelayoutRoot, m_layoutRoot)) {
2423 // Re-root at newRelayoutRoot.
2424 m_layoutRoot->markContainingBlocksForLayout(false, &newRelayoutRoot);
2425 m_layoutRoot = &newRelayoutRoot;
2426 ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout());
2427 InspectorInstrumentation::didInvalidateLayout(&frame());
2431 // Just do a full relayout.
2432 m_layoutRoot->markContainingBlocksForLayout(false);
2434 newRelayoutRoot.markContainingBlocksForLayout(false);
2435 InspectorInstrumentation::didInvalidateLayout(&frame());
2438 bool FrameView::layoutPending() const
2440 return m_layoutTimer.isActive();
2443 bool FrameView::needsLayout() const
2445 // This can return true in cases where the document does not have a body yet.
2446 // Document::shouldScheduleLayout takes care of preventing us from scheduling
2447 // layout in that case.
2448 RenderView* renderView = this->renderView();
2449 return layoutPending()
2450 || (renderView && renderView->needsLayout())
2452 || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
2455 void FrameView::setNeedsLayout()
2457 if (m_deferSetNeedsLayouts) {
2458 m_setNeedsLayoutWasDeferred = true;
2462 if (RenderView* renderView = this->renderView())
2463 renderView->setNeedsLayout();
2466 void FrameView::unscheduleRelayout()
2468 if (!m_layoutTimer.isActive())
2471 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2472 if (!frame().document()->ownerElement())
2473 printf("Layout timer unscheduled at %d\n", frame().document()->elapsedTime());
2476 m_layoutTimer.stop();
2477 m_delayedLayout = false;
2480 #if ENABLE(REQUEST_ANIMATION_FRAME)
2481 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
2483 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
2484 frame->view()->serviceScrollAnimations();
2485 frame->animation().serviceAnimations();
2488 Vector<RefPtr<Document>> documents;
2489 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext())
2490 documents.append(frame->document());
2492 for (size_t i = 0; i < documents.size(); ++i)
2493 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
2497 bool FrameView::isTransparent() const
2499 return m_isTransparent;
2502 void FrameView::setTransparent(bool isTransparent)
2504 m_isTransparent = isTransparent;
2507 bool FrameView::hasOpaqueBackground() const
2509 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
2512 Color FrameView::baseBackgroundColor() const
2514 return m_baseBackgroundColor;
2517 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
2519 if (!backgroundColor.isValid())
2520 m_baseBackgroundColor = Color::white;
2522 m_baseBackgroundColor = backgroundColor;
2524 recalculateScrollbarOverlayStyle();
2527 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
2529 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
2530 if (FrameView* view = frame->view()) {
2531 view->setTransparent(transparent);
2532 view->setBaseBackgroundColor(backgroundColor);
2537 bool FrameView::shouldUpdateWhileOffscreen() const
2539 return m_shouldUpdateWhileOffscreen;
2542 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
2544 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
2547 bool FrameView::shouldUpdate(bool immediateRequested) const
2549 if (!immediateRequested && isOffscreen() && !shouldUpdateWhileOffscreen())
2554 void FrameView::scrollToAnchor()
2556 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
2560 if (!anchorNode->renderer())
2564 if (anchorNode != frame().document())
2565 rect = anchorNode->boundingBox();
2567 // Scroll nested layers and frames to reveal the anchor.
2568 // Align to the top and to the closest side (this matches other browsers).
2569 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
2571 if (AXObjectCache* cache = frame().document()->existingAXObjectCache())
2572 cache->handleScrolledToAnchor(anchorNode.get());
2574 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
2575 m_maintainScrollPositionAnchor = anchorNode;
2578 void FrameView::updateEmbeddedObject(RenderEmbeddedObject& embeddedObject)
2580 // No need to update if it's already crashed or known to be missing.
2581 if (embeddedObject.isPluginUnavailable())
2584 HTMLFrameOwnerElement& element = embeddedObject.frameOwnerElement();
2586 if (embeddedObject.isSnapshottedPlugIn()) {
2587 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element)) {
2588 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2589 pluginElement.checkSnapshotStatus();
2594 auto weakRenderer = embeddedObject.createWeakPtr();
2596 // FIXME: This could turn into a real virtual dispatch if we defined
2597 // updateWidget(PluginCreationOption) on HTMLElement.
2598 if (isHTMLObjectElement(element) || isHTMLEmbedElement(element) || isHTMLAppletElement(element)) {
2599 HTMLPlugInImageElement& pluginElement = toHTMLPlugInImageElement(element);
2600 if (pluginElement.needsCheckForSizeChange()) {
2601 pluginElement.checkSnapshotStatus();
2604 if (pluginElement.needsWidgetUpdate())
2605 pluginElement.updateWidget(CreateAnyWidgetType);
2608 // FIXME: It is not clear that Media elements need or want this updateWidget() call.
2609 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2610 else if (element.isMediaElement())
2611 toHTMLMediaElement(element).updateWidget(CreateAnyWidgetType);
2614 ASSERT_NOT_REACHED();
2616 // It's possible the renderer was destroyed below updateWidget() since loading a plugin may execute arbitrary JavaScript.
2620 embeddedObject.updateWidgetPosition();
2623 bool FrameView::updateEmbeddedObjects()
2625 if (m_nestedLayoutCount > 1 || !m_embeddedObjectsToUpdate || m_embeddedObjectsToUpdate->isEmpty())
2628 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
2630 // Insert a marker for where we should stop.
2631 ASSERT(!m_embeddedObjectsToUpdate->contains(nullptr));
2632 m_embeddedObjectsToUpdate->add(nullptr);
2634 while (!m_embeddedObjectsToUpdate->isEmpty()) {
2635 RenderEmbeddedObject* embeddedObject = m_embeddedObjectsToUpdate->takeFirst();
2636 if (!embeddedObject)
2638 updateEmbeddedObject(*embeddedObject);
2641 return m_embeddedObjectsToUpdate->isEmpty();
2644 void FrameView::flushAnyPendingPostLayoutTasks()
2646 if (!m_postLayoutTasksTimer.isActive())
2649 performPostLayoutTasks();
2652 void FrameView::performPostLayoutTasks()
2654 m_postLayoutTasksTimer.stop();
2656 frame().selection().setCaretRectNeedsUpdate();
2657 frame().selection().updateAppearance();
2659 LayoutMilestones requestedMilestones = 0;
2660 LayoutMilestones milestonesAchieved = 0;
2661 Page* page = frame().page();
2663 requestedMilestones = page->requestedLayoutMilestones();
2665 if (m_nestedLayoutCount <= 1 && frame().document()->documentElement()) {
2666 if (m_firstLayoutCallbackPending) {
2667 m_firstLayoutCallbackPending = false;
2668 frame().loader().didFirstLayout();
2669 if (requestedMilestones & DidFirstLayout)
2670 milestonesAchieved |= DidFirstLayout;
2671 if (frame().isMainFrame())
2672 page->startCountingRelevantRepaintedObjects();
2674 updateIsVisuallyNonEmpty();
2676 // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2677 if (m_isVisuallyNonEmpty && !frame().document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2678 m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2679 if (requestedMilestones & DidFirstVisuallyNonEmptyLayout)
2680 milestonesAchieved |= DidFirstVisuallyNonEmptyLayout;
2684 if (milestonesAchieved && frame().isMainFrame())
2685 frame().loader().didLayout(milestonesAchieved);
2687 #if ENABLE(FONT_LOAD_EVENTS)
2688 if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
2689 frame().document()->fontloader()->didLayout();
2692 // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this
2693 // with didLayout(LayoutMilestones).
2694 frame().loader().client().dispatchDidLayout();
2696 updateWidgetPositions();
2698 // layout() protects FrameView, but it still can get destroyed when updateEmbeddedObjects()
2699 // is called through the post layout timer.
2700 Ref<FrameView> protect(*this);
2702 for (unsigned i = 0; i < maxUpdateEmbeddedObjectsIterations; i++) {
2703 if (updateEmbeddedObjects())
2708 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2709 scrollingCoordinator->frameViewLayoutUpdated(this);
2712 #if USE(ACCELERATED_COMPOSITING)
2713 if (RenderView* renderView = this->renderView()) {
2714 if (renderView->usesCompositing())
2715 renderView->compositor().frameViewDidLayout();
2721 sendResizeEventIfNeeded();
2724 void FrameView::sendResizeEventIfNeeded()
2726 RenderView* renderView = this->renderView();
2727 if (!renderView || renderView->printing())
2729 if (frame().page() && frame().page()->chrome().client().isSVGImageChromeClient())
2732 IntSize currentSize;
2733 if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
2734 currentSize = fixedLayoutSize();
2736 currentSize = visibleContentRect(IncludeScrollbars).size();
2738 float currentZoomFactor = renderView->style().zoom();
2739 bool shouldSendResizeEvent = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor);
2741 m_lastViewportSize = currentSize;
2742 m_lastZoomFactor = currentZoomFactor;
2744 if (!shouldSendResizeEvent)
2747 bool isMainFrame = frame().isMainFrame();
2748 bool canSendResizeEventSynchronously = isMainFrame && !isInLayout();
2750 // If we resized during layout, queue up a resize event for later, otherwise fire it right away.
2751 RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false);
2752 if (canSendResizeEventSynchronously)
2753 frame().document()->dispatchWindowEvent(resizeEvent.release(), frame().document()->domWindow());
2755 frame().document()->enqueueWindowEvent(resizeEvent.release());
2757 #if ENABLE(INSPECTOR)
2758 Page* page = frame().page();
2759 if (InspectorInstrumentation::hasFrontends() && isMainFrame) {
2760 if (InspectorClient* inspectorClient = page ? page->inspectorController()->inspectorClient() : 0)
2761 inspectorClient->didResizeMainFrame(&frame());
2766 void FrameView::willStartLiveResize()
2768 ScrollView::willStartLiveResize();
2769 adjustTiledBackingCoverage();
2772 void FrameView::willEndLiveResize()
2774 ScrollView::willEndLiveResize();
2775 adjustTiledBackingCoverage();
2778 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2780 performPostLayoutTasks();
2783 void FrameView::autoSizeIfEnabled()
2785 if (!m_shouldAutoSize)
2791 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2793 Document* document = frame().document();
2797 RenderView* documentView = document->renderView();
2798 Element* documentElement = document->documentElement();
2799 if (!documentView || !documentElement)
2802 // Start from the minimum size and allow it to grow.
2803 resize(m_minAutoSize.width(), m_minAutoSize.height());
2805 IntSize size = frameRect().size();
2807 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2808 // which may result in a height change during the second iteration.
2809 for (int i = 0; i < 2; i++) {
2810 // Update various sizes including contentsSize, scrollHeight, etc.
2811 document->updateLayoutIgnorePendingStylesheets();
2812 int width = documentView->minPreferredLogicalWidth();
2813 int height = documentView->documentRect().height();
2814 IntSize newSize(width, height);
2816 // Check to see if a scrollbar is needed for a given dimension and
2817 // if so, increase the other dimension to account for the scrollbar.
2818 // Since the dimensions are only for the view rectangle, once a
2819 // dimension exceeds the maximum, there is no need to increase it further.
2820 if (newSize.width() > m_maxAutoSize.width()) {
2821 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2822 if (!localHorizontalScrollbar)
2823 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2824 if (!localHorizontalScrollbar->isOverlayScrollbar())
2825 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
2827 // Don't bother checking for a vertical scrollbar because the width is at
2828 // already greater the maximum.
2829 } else if (newSize.height() > m_maxAutoSize.height()) {
2830 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
2831 if (!localVerticalScrollbar)
2832 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
2833 if (!localVerticalScrollbar->isOverlayScrollbar())
2834 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
2836 // Don't bother checking for a horizontal scrollbar because the height is
2837 // already greater the maximum.
2840 // Ensure the size is at least the min bounds.
2841 newSize = newSize.expandedTo(m_minAutoSize);
2843 // Bound the dimensions by the max bounds and determine what scrollbars to show.
2844 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
2845 if (newSize.width() > m_maxAutoSize.width()) {
2846 newSize.setWidth(m_maxAutoSize.width());
2847 horizonalScrollbarMode = ScrollbarAlwaysOn;
2849 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
2850 if (newSize.height() > m_maxAutoSize.height()) {
2851 newSize.setHeight(m_maxAutoSize.height());
2852 verticalScrollbarMode = ScrollbarAlwaysOn;
2855 if (newSize == size)
2858 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
2859 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
2860 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
2861 && !frame().loader().isComplete() && (newSize.height() < size.height() || newSize.width() < size.width()))
2864 resize(newSize.width(), newSize.height());
2865 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
2866 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
2867 setVerticalScrollbarLock(false);
2868 setHorizontalScrollbarLock(false);
2869 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
2872 m_autoSizeContentSize = contentsSize();
2874 if (m_autoSizeFixedMinimumHeight) {
2875 resize(m_autoSizeContentSize.width(), std::max(m_autoSizeFixedMinimumHeight, m_autoSizeContentSize.height()));
2876 document->updateLayoutIgnorePendingStylesheets();
2879 m_didRunAutosize = true;
2882 void FrameView::setAutoSizeFixedMinimumHeight(int fixedMinimumHeight)
2884 if (m_autoSizeFixedMinimumHeight == fixedMinimumHeight)
2887 m_autoSizeFixedMinimumHeight = fixedMinimumHeight;
2892 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2894 if (!m_viewportRenderer)
2897 if (m_overflowStatusDirty) {
2898 m_horizontalOverflow = horizontalOverflow;
2899 m_verticalOverflow = verticalOverflow;
2900 m_overflowStatusDirty = false;
2904 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2905 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2907 if (horizontalOverflowChanged || verticalOverflowChanged) {
2908 m_horizontalOverflow = horizontalOverflow;
2909 m_verticalOverflow = verticalOverflow;
2911 RefPtr<OverflowEvent> overflowEvent = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
2912 verticalOverflowChanged, verticalOverflow);
2913 overflowEvent->setTarget(m_viewportRenderer->element());
2915 frame().document()->enqueueOverflowEvent(overflowEvent.release());
2920 const Pagination& FrameView::pagination() const
2922 if (m_pagination != Pagination())
2923 return m_pagination;
2925 if (frame().isMainFrame())
2926 return frame().page()->pagination();
2928 return m_pagination;
2931 void FrameView::setPagination(const Pagination& pagination)
2933 if (m_pagination == pagination)
2936 m_pagination = pagination;
2938 frame().document()->styleResolverChanged(DeferRecalcStyle);
2941 IntRect FrameView::windowClipRect(bool clipToContents) const
2943 ASSERT(frame().view() == this);
2945 if (paintsEntireContents())
2946 return IntRect(IntPoint(), totalContentsSize());
2948 // Set our clip rect to be our contents.
2949 IntRect clipRect = contentsToWindow(visibleContentRect(clipToContents ? ExcludeScrollbars : IncludeScrollbars));
2950 if (!frame().ownerElement())
2953 // Take our owner element and get its clip rect.
2954 HTMLFrameOwnerElement* ownerElement = frame().ownerElement();
2955 if (FrameView* parentView = ownerElement->document().view())
2956 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
2960 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
2962 // The renderer can sometimes be null when style="display:none" interacts
2963 // with external content and plugins.
2964 if (!ownerElement->renderer())
2965 return windowClipRect();
2967 // If we have no layer, just return our window clip rect.
2968 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2969 if (!enclosingLayer)
2970 return windowClipRect();
2972 // Apply the clip from the layer.
2974 if (clipToLayerContents)
2975 clipRect = pixelSnappedIntRect(enclosingLayer->childrenClipRect());
2977 clipRect = pixelSnappedIntRect(enclosingLayer->selfClipRect());
2978 clipRect = contentsToWindow(clipRect);
2979 return intersection(clipRect, windowClipRect());
2982 bool FrameView::isActive() const
2984 Page* page = frame().page();
2985 return page && page->focusController().isActive();
2988 bool FrameView::updatesScrollLayerPositionOnMainThread() const
2990 if (Page* page = frame().page()) {
2991 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2992 return scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread();
2998 void FrameView::scrollTo(const IntSize& newOffset)
3000 LayoutSize offset = scrollOffset();
3001 ScrollView::scrollTo(newOffset);
3002 if (offset != scrollOffset())
3003 scrollPositionChanged();
3004 frame().loader().client().didChangeScrollOffset();
3007 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
3009 // Add in our offset within the FrameView.
3010 IntRect dirtyRect = rect;
3011 dirtyRect.moveBy(scrollbar->location());
3012 invalidateRect(dirtyRect);
3015 IntRect FrameView::windowResizerRect() const
3017 if (Page* page = frame().page())
3018 return page->chrome().windowResizerRect();
3022 float FrameView::visibleContentScaleFactor() const
3024 if (!frame().isMainFrame() || !frame().settings().delegatesPageScaling())
3027 return frame().page()->pageScaleFactor();
3030 void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
3032 if (!frame().isMainFrame())
3035 frame().page()->chrome().client().notifyScrollerThumbIsVisibleInRect(scrollerThumb);
3038 ScrollableArea* FrameView::enclosingScrollableArea() const
3040 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
3044 IntRect FrameView::scrollableAreaBoundingBox() const
3046 RenderWidget* ownerRenderer = frame().ownerRenderer();
3050 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
3053 bool FrameView::isScrollable()
3056 // 1) If there an actual overflow.
3057 // 2) display:none or visibility:hidden set to self or inherited.
3058 // 3) overflow{-x,-y}: hidden;
3059 // 4) scrolling: no;
3062 IntSize totalContentsSize = this->totalContentsSize();
3063 IntSize visibleContentSize = visibleContentRect().size();
3064 if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width()))
3068 HTMLFrameOwnerElement* owner = frame().ownerElement();
3069 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
3073 ScrollbarMode horizontalMode;
3074 ScrollbarMode verticalMode;
3075 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
3076 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
3082 void FrameView::updateScrollableAreaSet()
3084 // That ensures that only inner frames are cached.
3085 FrameView* parentFrameView = this->parentFrameView();
3086 if (!parentFrameView)
3089 if (!isScrollable()) {
3090 parentFrameView->removeScrollableArea(this);
3094 parentFrameView->addScrollableArea(this);
3097 bool FrameView::shouldSuspendScrollAnimations() const
3099 return frame().loader().state() != FrameStateComplete;
3102 void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate)
3104 if (!frame().isMainFrame())
3107 frame().page()->chrome().client().recommendedScrollbarStyleDidChange(newStyle);
3110 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
3113 void FrameView::notifyPageThatContentAreaWillPaint() const
3115 Page* page = frame().page();
3119 contentAreaWillPaint();
3121 if (!m_scrollableAreas)
3124 for (auto& scrollableArea : *m_scrollableAreas)
3125 scrollableArea->contentAreaWillPaint();
3128 bool FrameView::scrollAnimatorEnabled() const
3130 #if ENABLE(SMOOTH_SCROLLING)
3131 if (Page* page = frame().page())
3132 return page->settings().scrollAnimatorEnabled();
3138 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
3139 void FrameView::updateAnnotatedRegions()
3141 Document* document = frame().document();
3142 if (!document->hasAnnotatedRegions())
3144 Vector<AnnotatedRegionValue> newRegions;
3145 document->renderBox()->collectAnnotatedRegions(newRegions);
3146 if (newRegions == document->annotatedRegions())
3148 document->setAnnotatedRegions(newRegions);
3149 Page* page = frame().page();
3152 page->chrome().client().annotatedRegionsChanged();
3156 void FrameView::updateScrollCorner()
3158 RenderElement* renderer = 0;
3159 RefPtr<RenderStyle> cornerStyle;
3160 IntRect cornerRect = scrollCornerRect();
3162 if (!cornerRect.isEmpty()) {
3163 // Try the <body> element first as a scroll corner source.
3164 Document* doc = frame().document();
3165 Element* body = doc ? doc->body() : 0;
3166 if (body && body->renderer()) {
3167 renderer = body->renderer();
3168 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3172 // If the <body> didn't have a custom style, then the root element might.
3173 Element* docElement = doc ? doc->documentElement() : 0;
3174 if (docElement && docElement->renderer()) {
3175 renderer = docElement->renderer();
3176 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3181 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
3182 if (RenderWidget* renderer = frame().ownerRenderer())
3183 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &renderer->style());
3188 if (!m_scrollCorner) {
3189 m_scrollCorner = new RenderScrollbarPart(renderer->document(), cornerStyle.releaseNonNull());
3190 m_scrollCorner->initializeStyle();
3192 m_scrollCorner->setStyle(cornerStyle.releaseNonNull());
3193 invalidateScrollCorner(cornerRect);
3194 } else if (m_scrollCorner) {
3195 m_scrollCorner->destroy();
3199 ScrollView::updateScrollCorner();
3202 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
3204 if (context->updatingControlTints()) {
3205 updateScrollCorner();
3209 if (m_scrollCorner) {
3210 if (frame().isMainFrame())
3211 context->fillRect(cornerRect, baseBackgroundColor(), ColorSpaceDeviceRGB);
3212 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
3216 ScrollView::paintScrollCorner(context, cornerRect);
3219 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
3221 if (bar->isCustomScrollbar() && frame().isMainFrame()) {
3222 IntRect toFill = bar->frameRect();
3223 toFill.intersect(rect);
3224 context->fillRect(toFill, baseBackgroundColor(), ColorSpaceDeviceRGB);
3227 ScrollView::paintScrollbar(context, bar, rect);
3230 Color FrameView::documentBackgroundColor() const
3232 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
3233 // the document and the body against the base background color of the frame view.
3234 // Background images are unfortunately impractical to include.
3236 // Return invalid Color objects whenever there is insufficient information.
3237 if (!frame().document())
3240 Element* htmlElement = frame().document()->documentElement();
3241 Element* bodyElement = frame().document()->body();
3243 // Start with invalid colors.
3244 Color htmlBackgroundColor;
3245 Color bodyBackgroundColor;
3246 if (htmlElement && htmlElement->renderer())
3247 htmlBackgroundColor = htmlElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3248 if (bodyElement && bodyElement->renderer())
3249 bodyBackgroundColor = bodyElement->renderer()->style().visitedDependentColor(CSSPropertyBackgroundColor);
3251 if (!bodyBackgroundColor.isValid()) {
3252 if (!htmlBackgroundColor.isValid())
3254 return baseBackgroundColor().blend(htmlBackgroundColor);
3257 if (!htmlBackgroundColor.isValid())
3258 return baseBackgroundColor().blend(bodyBackgroundColor);
3260 // We take the aggregate of the base background color
3261 // the <html> background color, and the <body>
3262 // background color to find the document color. The
3263 // addition of the base background color is not
3264 // technically part of the document background, but it
3265 // otherwise poses problems when the aggregate is not
3267 return baseBackgroundColor().blend(htmlBackgroundColor).blend(bodyBackgroundColor);
3270 bool FrameView::hasCustomScrollbars() const
3272 for (auto& widget : children()) {
3273 if (widget->isFrameView()) {
3274 if (toFrameView(*widget).hasCustomScrollbars())
3276 } else if (widget->isScrollbar()) {
3277 if (toScrollbar(*widget).isCustomScrollbar())
3285 FrameView* FrameView::parentFrameView() const
3290 if (Frame* parentFrame = frame().tree().parent())
3291 return parentFrame->view();
3296 bool FrameView::isInChildFrameWithFrameFlattening() const
3298 if (!parent() || !frame().ownerElement())
3301 // Frame flattening applies when the owner element is either in a frameset or
3302 // an iframe with flattening parameters.
3303 if (frame().ownerElement()->hasTagName(iframeTag)) {
3304 RenderIFrame* iframeRenderer = toRenderIFrame(frame().ownerElement()->renderWidget());
3305 if (iframeRenderer->flattenFrame() || iframeRenderer->isSeamless())
3309 if (!frameFlatteningEnabled())
3312 if (frame().ownerElement()->hasTagName(frameTag))
3318 void FrameView::startLayoutAtMainFrameViewIfNeeded(bool allowSubtree)
3320 // When we start a layout at the child level as opposed to the topmost frame view and this child
3321 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
3322 // will hit this view eventually.
3323 FrameView* parentView = parentFrameView();
3327 // In the middle of parent layout, no need to restart from topmost.
3328 if (parentView->m_nestedLayoutCount)
3331 // Parent tree is clean. Starting layout from it would have no effect.
3332 if (!parentView->needsLayout())
3335 while (parentView->parentFrameView())
3336 parentView = parentView->parentFrameView();
3338 parentView->layout(allowSubtree);
3340 RenderElement* root = m_layoutRoot ? m_layoutRoot : frame().document()->renderView();
3341 ASSERT_UNUSED(root, !root->needsLayout());
3344 void FrameView::updateControlTints()
3346 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
3347 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
3348 // This is only done if the theme supports control tinting. It's up to the theme and platform
3349 // to define when controls get the tint and to call this function when that changes.
3351 // Optimize the common case where we bring a window to the front while it's still empty.
3352 if (frame().document()->url().isEmpty())
3355 RenderView* renderView = this->renderView();
3356 if ((renderView && renderView->theme().supportsControlTints()) || hasCustomScrollbars())
3357 paintControlTints();
3360 void FrameView::paintControlTints()
3364 PlatformGraphicsContext* const noContext = 0;
3365 GraphicsContext context(noContext);
3366 context.setUpdatingControlTints(true);
3367 if (platformWidget())
3368 paintContents(&context, visibleContentRect());
3370 paint(&context, frameRect());
3373 bool FrameView::wasScrolledByUser() const
3375 return m_wasScrolledByUser;
3378 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
3380 if (m_inProgrammaticScroll)
3382 m_maintainScrollPositionAnchor = 0;
3383 if (m_wasScrolledByUser == wasScrolledByUser)
3385 m_wasScrolledByUser = wasScrolledByUser;
3386 adjustTiledBackingCoverage();
3389 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
3391 Document* document = frame().document();
3395 if (document->printing())
3396 fillWithRed = false; // Printing, don't fill with red (can't remember why).
3397 else if (frame().ownerElement())
3398 fillWithRed = false; // Subframe, don't fill with red.
3399 else if (isTransparent())
3400 fillWithRed = false; // Transparent, don't fill with red.
3401 else if (m_paintBehavior & PaintBehaviorSelectionOnly)
3402 fillWithRed = false; // Selections are transparent, don't fill with red.
3403 else if (m_nodeToDraw)
3404 fillWithRed = false; // Element images are transparent, don't fill with red.
3409 p->fillRect(rect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
3412 RenderView* renderView = this->renderView();
3414 LOG_ERROR("called FrameView::paint with nil renderer");
3418 ASSERT(!needsLayout());
3422 if (!p->paintingDisabled())
3423 InspectorInstrumentation::willPaint(renderView);
3425 bool isTopLevelPainter = !sCurrentPaintTimeStamp;
3426 if (isTopLevelPainter)
3427 sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
3429 FontCachePurgePreventer fontCachePurgePreventer;
3431 #if USE(ACCELERATED_COMPOSITING)
3432 if (!p->paintingDisabled() && !document->printing())
3433 flushCompositingStateForThisFrame(&frame());
3436 PaintBehavior oldPaintBehavior = m_paintBehavior;
3438 if (FrameView* parentView = parentFrameView()) {
3439 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
3440 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3443 if (m_paintBehavior == PaintBehaviorNormal)
3444 document->markers().invalidateRenderedRectsForMarkersInRect(rect);
3446 if (document->printing())
3447 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
3449 bool flatteningPaint = m_paintBehavior & PaintBehaviorFlattenCompositingLayers;
3450 bool isRootFrame = !frame().ownerElement();
3451 if (flatteningPaint && isRootFrame)
3452 notifyWidgetsInAllFrames(WillPaintFlattened);
3454 ASSERT(!m_isPainting);
3455 m_isPainting = true;
3457 // m_nodeToDraw is used to draw only one element (and its descendants)
3458 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
3459 RenderLayer* rootLayer = renderView->layer();
3462 RenderElement::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(&rootLayer->renderer());
3465 rootLayer->paint(p, rect, m_paintBehavior, eltRenderer);
3467 if (rootLayer->containsDirtyOverlayScrollbars())
3468 rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, eltRenderer);
3470 m_isPainting = false;
3472 if (flatteningPaint && isRootFrame)
3473 notifyWidgetsInAllFrames(DidPaintFlattened);
3475 m_paintBehavior = oldPaintBehavior;
3476 m_lastPaintTime = monotonicallyIncreasingTime();
3478 // Regions may have changed as a result of the visibility/z-index of element changing.
3479 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
3480 if (document->annotatedRegionsDirty())
3481 updateAnnotatedRegions();
3484 if (isTopLevelPainter)
3485 sCurrentPaintTimeStamp = 0;
3487 if (!p->paintingDisabled()) {
3488 InspectorInstrumentation::didPaint(renderView, p, rect);
3489 // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623
3490 firePaintRelatedMilestones();
3494 void FrameView::setPaintBehavior(PaintBehavior behavior)
3496 m_paintBehavior = behavior;
3499 PaintBehavior FrameView::paintBehavior() const
3501 return m_paintBehavior;
3504 bool FrameView::isPainting() const
3506 return m_isPainting;
3509 // FIXME: change this to use the subtreePaint terminology.
3510 void FrameView::setNodeToDraw(Node* node)
3512 m_nodeToDraw = node;
3515 void FrameView::paintContentsForSnapshot(GraphicsContext* context, const IntRect& imageRect, SelectionInSnapshot shouldPaintSelection, CoordinateSpaceForSnapshot coordinateSpace)
3517 updateLayoutAndStyleIfNeededRecursive();
3519 // Cache paint behavior and set a new behavior appropriate for snapshots.
3520 PaintBehavior oldBehavior = paintBehavior();
3521 setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
3523 // If the snapshot should exclude selection, then we'll clear the current selection
3524 // in the render tree only. This will allow us to restore the selection from the DOM
3525 // after we paint the snapshot.
3526 if (shouldPaintSelection == ExcludeSelection) {
3527 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
3528 if (RenderView* root = frame->contentRenderer())
3529 root->clearSelection();
3533 if (coordinateSpace == DocumentCoordinates)
3534 paintContents(context, imageRect);
3536 // A snapshot in ViewCoordinates will include a scrollbar, and the snapshot will contain
3537 // whatever content the document is currently scrolled to.
3538 paint(context, imageRect);
3541 // Restore selection.
3542 if (shouldPaintSelection == ExcludeSelection) {
3543 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get()))
3544 frame->selection().updateAppearance();
3547 // Restore cached paint behavior.
3548 setPaintBehavior(oldBehavior);
3551 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
3553 if (context->paintingDisabled())
3556 if (frame().document()->printing())
3559 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
3562 void FrameView::updateLayoutAndStyleIfNeededRecursive()
3564 // We have to crawl our entire tree looking for any FrameViews that need
3565 // layout and make sure they are up to date.
3566 // Mac actually tests for intersection with the dirty region and tries not to
3567 // update layout for frames that are outside the dirty region. Not only does this seem
3568 // pointless (since those frames will have set a zero timer to layout anyway), but
3569 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
3570 // region but then become included later by the second frame adding rects to the dirty region
3571 // when it lays out.
3573 frame().document()->updateStyleIfNeeded();
3578 // Grab a copy of the children() set, as it may be mutated by the following updateLayoutAndStyleIfNeededRecursive
3579 // calls, as they can potentially re-enter a layout of the parent frame view, which may add/remove scrollbars
3580 // and thus mutates the children() set.
3581 Vector<Ref<FrameView>, 16> childViews;
3582 childViews.reserveInitialCapacity(children().size());
3583 for (auto& widget : children()) {
3584 if (widget->isFrameView())
3585 childViews.uncheckedAppend(toFrameView(*widget));
3588 for (unsigned i = 0; i < childViews.size(); ++i)
3589 childViews[i]->updateLayoutAndStyleIfNeededRecursive();
3591 // updateLayoutAndStyleIfNeededRecursive is called when we need to make sure style and layout are up-to-date before
3592 // painting, so we need to flush out any deferred repaints too.
3593 flushDeferredRepaints();
3595 // When frame flattening is on, child frame can mark parent frame dirty. In such case, child frame
3596 // needs to call layout on parent frame recursively.
3597 // This assert ensures that parent frames are clean, when child frames finished updating layout and style.
3598 ASSERT(!needsLayout());
3601 bool FrameView::qualifiesAsVisuallyNonEmpty() const
3604 Element* documentElement = frame().document()->documentElement();
3605 if (!documentElement || !documentElement->renderer())
3608 // Ensure that we always get marked visually non-empty eventually.
3609 if (!frame().document()->parsing() && frame().loader().stateMachine()->committedFirstRealDocumentLoad())
3612 // Require the document to grow a bit.
3613 static const int documentHeightThreshold = 200;
3614 if (documentElement->renderBox()->layoutOverflowRect().pixelSnappedHeight() < documentHeightThreshold)
3617 // The first few hundred characters rarely contain the interesting content of the page.
3618 if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold)
3620 // Use a threshold value to prevent very small amounts of visible content&n