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 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 "core/frame/FrameView.h"
30 #include "core/HTMLNames.h"
31 #include "core/MediaTypeNames.h"
32 #include "core/accessibility/AXObjectCache.h"
33 #include "core/css/FontFaceSet.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/DocumentMarkerController.h"
36 #include "core/dom/Fullscreen.h"
37 #include "core/editing/FrameSelection.h"
38 #include "core/editing/RenderedPosition.h"
39 #include "core/events/OverflowEvent.h"
40 #include "core/fetch/ResourceFetcher.h"
41 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
42 #include "core/frame/FrameHost.h"
43 #include "core/frame/LocalFrame.h"
44 #include "core/frame/Settings.h"
45 #include "core/html/HTMLFrameElement.h"
46 #include "core/html/HTMLPlugInElement.h"
47 #include "core/html/parser/TextResourceDecoder.h"
48 #include "core/inspector/InspectorInstrumentation.h"
49 #include "core/inspector/InspectorTraceEvents.h"
50 #include "core/loader/FrameLoader.h"
51 #include "core/loader/FrameLoaderClient.h"
52 #include "core/page/Chrome.h"
53 #include "core/page/ChromeClient.h"
54 #include "core/page/EventHandler.h"
55 #include "core/page/FocusController.h"
56 #include "core/page/FrameTree.h"
57 #include "core/page/Page.h"
58 #include "core/page/scrolling/ScrollingCoordinator.h"
59 #include "core/paint/FramePainter.h"
60 #include "core/rendering/RenderCounter.h"
61 #include "core/rendering/RenderEmbeddedObject.h"
62 #include "core/rendering/RenderLayer.h"
63 #include "core/rendering/RenderListBox.h"
64 #include "core/rendering/RenderPart.h"
65 #include "core/rendering/RenderScrollbar.h"
66 #include "core/rendering/RenderScrollbarPart.h"
67 #include "core/rendering/RenderTheme.h"
68 #include "core/rendering/RenderView.h"
69 #include "core/rendering/TextAutosizer.h"
70 #include "core/rendering/compositing/CompositedLayerMapping.h"
71 #include "core/rendering/compositing/CompositedSelectionBound.h"
72 #include "core/rendering/compositing/RenderLayerCompositor.h"
73 #include "core/rendering/style/RenderStyle.h"
74 #include "core/rendering/svg/RenderSVGRoot.h"
75 #include "core/svg/SVGDocumentExtensions.h"
76 #include "core/svg/SVGSVGElement.h"
77 #include "platform/HostWindow.h"
78 #include "platform/RuntimeEnabledFeatures.h"
79 #include "platform/ScriptForbiddenScope.h"
80 #include "platform/TraceEvent.h"
81 #include "platform/fonts/FontCache.h"
82 #include "platform/geometry/FloatRect.h"
83 #include "platform/graphics/GraphicsContext.h"
84 #include "platform/graphics/GraphicsContextStateSaver.h"
85 #include "platform/graphics/GraphicsLayer.h"
86 #include "platform/graphics/GraphicsLayerDebugInfo.h"
87 #include "platform/scroll/ScrollAnimator.h"
88 #include "platform/scroll/ScrollbarTheme.h"
89 #include "platform/text/TextStream.h"
90 #include "wtf/CurrentTime.h"
91 #include "wtf/StdLibExtras.h"
92 #include "wtf/TemporaryChange.h"
96 using namespace HTMLNames;
98 double FrameView::s_currentFrameTimeStamp = 0.0;
100 // The maximum number of updateWidgets iterations that should be done before returning.
101 static const unsigned maxUpdateWidgetsIterations = 2;
102 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
104 FrameView::FrameView(LocalFrame* frame)
106 , m_canHaveScrollbars(true)
107 , m_slowRepaintObjectCount(0)
108 , m_hasPendingLayout(false)
109 , m_layoutSubtreeRoot(0)
110 , m_inSynchronousPostLayout(false)
111 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
112 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
113 , m_isTransparent(false)
114 , m_baseBackgroundColor(Color::white)
115 , m_mediaType(MediaTypeNames::screen)
116 , m_overflowStatusDirty(true)
117 , m_viewportRenderer(0)
118 , m_wasScrolledByUser(false)
119 , m_inProgrammaticScroll(false)
120 , m_safeToPropagateScrollToParent(true)
121 , m_isTrackingPaintInvalidations(false)
122 , m_scrollCorner(nullptr)
123 , m_visibleContentScaleFactor(1)
124 , m_inputEventsScaleFactorForEmulation(1)
125 , m_layoutSizeFixedToFrameSize(true)
126 , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
127 , m_topControlsViewportAdjustment(0)
128 , m_needsUpdateWidgetPositions(false)
129 #if ENABLE(OILPAN) && ENABLE(ASSERT)
130 , m_hasBeenDisposed(false)
132 , m_horizontalScrollbarMode(ScrollbarAuto)
133 , m_verticalScrollbarMode(ScrollbarAuto)
134 , m_horizontalScrollbarLock(false)
135 , m_verticalScrollbarLock(false)
136 , m_scrollbarsAvoidingResizer(0)
137 , m_scrollbarsSuppressed(false)
138 , m_inUpdateScrollbars(false)
139 , m_shouldDrawPanScrollIcon(false)
140 , m_clipsRepaints(true)
145 if (!m_frame->isMainFrame())
148 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
149 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed);
152 PassRefPtrWillBeRawPtr<FrameView> FrameView::create(LocalFrame* frame)
154 RefPtrWillBeRawPtr<FrameView> view = adoptRefWillBeNoop(new FrameView(frame));
156 return view.release();
159 PassRefPtrWillBeRawPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
161 RefPtrWillBeRawPtr<FrameView> view = adoptRefWillBeNoop(new FrameView(frame));
162 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
163 view->setLayoutSizeInternal(initialSize);
166 return view.release();
169 FrameView::~FrameView()
172 ASSERT(m_hasBeenDisposed);
174 // Verify that the LocalFrame has a different FrameView or
175 // that it is being detached and destructed.
176 ASSERT(frame().view() != this || !renderView());
181 void FrameView::dispose()
183 if (m_postLayoutTasksTimer.isActive())
184 m_postLayoutTasksTimer.stop();
186 if (m_didScrollTimer.isActive())
187 m_didScrollTimer.stop();
189 removeFromAXObjectCache();
191 // Custom scrollbars should already be destroyed at this point
192 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
193 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
195 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
196 setHasVerticalScrollbar(false);
198 ASSERT(!m_scrollCorner);
200 // FIXME: Do we need to do something here for OOPI?
201 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
202 if (ownerElement && ownerElement->ownedWidget() == this)
203 ownerElement->setWidget(nullptr);
205 disposeAutoSizeInfo();
206 #if ENABLE(OILPAN) && ENABLE(ASSERT)
207 m_hasBeenDisposed = true;
211 void FrameView::trace(Visitor* visitor)
214 visitor->trace(m_partUpdateSet);
215 visitor->trace(m_parts);
216 visitor->trace(m_frame);
217 visitor->trace(m_nodeToDraw);
218 visitor->trace(m_maintainScrollPositionAnchor);
219 visitor->trace(m_scrollCorner);
220 visitor->trace(m_autoSizeInfo);
221 visitor->trace(m_horizontalScrollbar);
222 visitor->trace(m_verticalScrollbar);
223 visitor->trace(m_children);
225 Widget::trace(visitor);
228 void FrameView::reset()
230 m_hasPendingLayout = false;
231 m_layoutSubtreeRoot = 0;
232 m_doFullPaintInvalidation = false;
233 m_layoutSchedulingEnabled = true;
234 m_inPerformLayout = false;
235 m_canInvalidatePaintDuringPerformLayout = false;
236 m_inSynchronousPostLayout = false;
238 m_nestedLayoutCount = 0;
239 m_postLayoutTasksTimer.stop();
240 m_updateWidgetsTimer.stop();
241 m_firstLayout = true;
242 m_firstLayoutCallbackPending = false;
243 m_wasScrolledByUser = false;
244 m_safeToPropagateScrollToParent = true;
245 m_lastViewportSize = IntSize();
246 m_lastZoomFactor = 1.0f;
247 m_isTrackingPaintInvalidations = false;
248 m_trackedPaintInvalidationRects.clear();
250 m_paintBehavior = PaintBehaviorNormal;
251 m_isPainting = false;
252 m_visuallyNonEmptyCharacterCount = 0;
253 m_visuallyNonEmptyPixelCount = 0;
254 m_isVisuallyNonEmpty = false;
255 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
256 m_maintainScrollPositionAnchor = nullptr;
257 m_viewportConstrainedObjects.clear();
260 void FrameView::removeFromAXObjectCache()
262 if (AXObjectCache* cache = axObjectCache()) {
264 cache->childrenChanged(m_frame->pagePopupOwner());
268 void FrameView::init()
272 m_size = LayoutSize();
274 // Propagate the marginwidth/height and scrolling modes to the view.
275 // FIXME: Do we need to do this for OOPI?
276 Element* ownerElement = m_frame->deprecatedLocalOwner();
277 if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) {
278 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
279 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
280 setCanHaveScrollbars(false);
284 void FrameView::prepareForDetach()
286 RELEASE_ASSERT(!isInPerformLayout());
288 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
289 scrollAnimator->cancelAnimations();
290 cancelProgrammaticScrollAnimation();
292 detachCustomScrollbars();
293 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
294 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
295 removeFromAXObjectCache();
297 if (m_frame->page()) {
298 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
299 scrollingCoordinator->willDestroyScrollableArea(this);
303 // FIXME: once/if dust settles, do this always (non-Oilpan)?
305 // FIXME: Oilpan: is this safe to dispose() if there are FrameView protections on the stack?
310 void FrameView::detachCustomScrollbars()
312 Scrollbar* horizontalBar = horizontalScrollbar();
313 if (horizontalBar && horizontalBar->isCustomScrollbar())
314 setHasHorizontalScrollbar(false);
316 Scrollbar* verticalBar = verticalScrollbar();
317 if (verticalBar && verticalBar->isCustomScrollbar())
318 setHasVerticalScrollbar(false);
320 if (m_scrollCorner) {
321 m_scrollCorner->destroy();
322 m_scrollCorner = nullptr;
326 void FrameView::recalculateCustomScrollbarStyle()
328 bool didStyleChange = false;
329 if (m_horizontalScrollbar && m_horizontalScrollbar->isCustomScrollbar()) {
330 m_horizontalScrollbar->styleChanged();
331 didStyleChange = true;
333 if (m_verticalScrollbar && m_verticalScrollbar->isCustomScrollbar()) {
334 m_verticalScrollbar->styleChanged();
335 didStyleChange = true;
337 if (didStyleChange) {
338 updateScrollbarGeometry();
339 updateScrollCorner();
340 positionScrollbarLayers();
344 void FrameView::recalculateScrollbarOverlayStyle()
346 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
347 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
349 Color backgroundColor = documentBackgroundColor();
350 // Reduce the background color from RGB to a lightness value
351 // and determine which scrollbar style to use based on a lightness
353 double hue, saturation, lightness;
354 backgroundColor.getHSL(hue, saturation, lightness);
356 overlayStyle = ScrollbarOverlayStyleLight;
358 if (oldOverlayStyle != overlayStyle)
359 setScrollbarOverlayStyle(overlayStyle);
362 void FrameView::clear()
365 setScrollbarsSuppressed(true);
368 bool FrameView::didFirstLayout() const
370 return !m_firstLayout;
373 void FrameView::invalidateRect(const IntRect& rect)
375 // For querying RenderLayer::compositingState() when invalidating scrollbars.
376 // FIXME: do all scrollbar invalidations after layout of all frames is complete. It's currently not recursively true.
377 DisableCompositingQueryAsserts disabler;
379 if (HostWindow* window = hostWindow())
380 window->invalidateContentsAndRootView(rect);
384 RenderPart* renderer = m_frame->ownerRenderer();
388 IntRect paintInvalidationRect = rect;
389 paintInvalidationRect.move(renderer->borderLeft() + renderer->paddingLeft(),
390 renderer->borderTop() + renderer->paddingTop());
391 renderer->invalidatePaintRectangle(paintInvalidationRect);
394 void FrameView::setFrameRect(const IntRect& newRect)
396 IntRect oldRect = frameRect();
397 if (newRect == oldRect)
400 // Autosized font sizes depend on the width of the viewing area.
401 bool autosizerNeedsUpdating = false;
402 if (newRect.width() != oldRect.width() && m_frame->isMainFrame() && m_frame->settings()->textAutosizingEnabled())
403 autosizerNeedsUpdating = true;
405 Widget::setFrameRect(newRect);
407 updateScrollbars(scrollOffsetDouble());
410 updateScrollableAreaSet();
412 if (autosizerNeedsUpdating) {
413 // This needs to be after the call to Widget::setFrameRect, because it reads the new width.
414 if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
415 textAutosizer->updatePageInfoInAllFrames();
418 if (RenderView* renderView = this->renderView()) {
419 if (renderView->usesCompositing())
420 renderView->compositor()->frameViewDidChangeSize();
423 viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
425 if (oldRect.size() != newRect.size()
426 && m_frame->isMainFrame()
427 && m_frame->settings()->pinchVirtualViewportEnabled())
428 page()->frameHost().pinchViewport().mainFrameDidChangeSize();
431 Page* FrameView::page() const
433 return frame().page();
436 RenderView* FrameView::renderView() const
438 return frame().contentRenderer();
441 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
443 m_canHaveScrollbars = canHaveScrollbars;
445 ScrollbarMode newHorizontalMode;
446 ScrollbarMode newVerticalMode;
448 scrollbarModes(newHorizontalMode, newVerticalMode);
450 if (canHaveScrollbars && newVerticalMode == ScrollbarAlwaysOff)
451 newVerticalMode = ScrollbarAuto;
452 else if (!canHaveScrollbars)
453 newVerticalMode = ScrollbarAlwaysOff;
455 if (canHaveScrollbars && newHorizontalMode == ScrollbarAlwaysOff)
456 newHorizontalMode = ScrollbarAuto;
457 else if (!canHaveScrollbars)
458 newHorizontalMode = ScrollbarAlwaysOff;
460 setScrollbarModes(newHorizontalMode, newVerticalMode);
463 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame)
465 customScrollbarElement = 0;
466 customScrollbarFrame = 0;
468 if (Settings* settings = m_frame->settings()) {
469 if (!settings->allowCustomScrollbarInMainFrame() && m_frame->isMainFrame())
473 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
474 Document* doc = m_frame->document();
476 // Try the <body> element first as a scrollbar source.
477 Element* body = doc ? doc->body() : 0;
478 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
479 customScrollbarElement = body;
483 // If the <body> didn't have a custom style, then the root element might.
484 Element* docElement = doc ? doc->documentElement() : 0;
485 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
486 customScrollbarElement = docElement;
490 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
491 RenderPart* frameRenderer = m_frame->ownerRenderer();
492 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) {
493 customScrollbarFrame = m_frame.get();
500 PassRefPtrWillBeRawPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
502 Element* customScrollbarElement = 0;
503 LocalFrame* customScrollbarFrame = 0;
504 if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
505 return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
507 // Nobody set a custom style, so we just use a native scrollbar.
508 return Scrollbar::create(this, orientation, RegularScrollbar);
511 void FrameView::setContentsSize(const IntSize& size)
513 if (size == contentsSize())
516 m_contentsSize = size;
517 updateScrollbars(scrollOffsetDouble());
518 updateOverhangAreas();
519 ScrollableArea::contentsResized();
521 Page* page = frame().page();
525 updateScrollableAreaSet();
527 page->chrome().contentsSizeChanged(m_frame.get(), size);
530 IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const
532 IntPoint maxScrollExtent(contentsSize().width() - scrollOrigin().x(), contentsSize().height() - scrollOrigin().y());
533 FloatSize scaledSize = unscaledVisibleContentSize();
535 scaledSize.scale(1 / scale);
537 IntPoint clampedOffset = offset;
538 clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize));
539 clampedOffset = clampedOffset.expandedTo(-scrollOrigin());
541 return clampedOffset;
544 void FrameView::adjustViewSize()
546 RenderView* renderView = this->renderView();
550 ASSERT(m_frame->view() == this);
552 const IntRect rect = renderView->documentRect();
553 const IntSize& size = rect.size();
554 setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
556 setContentsSize(size);
559 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
561 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
562 // overflow:hidden and overflow:scroll on <body> as applying to the document's
563 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
564 // use the root element.
566 EOverflow overflowX = o->style()->overflowX();
567 EOverflow overflowY = o->style()->overflowY();
569 if (o->isSVGRoot()) {
570 // Don't allow overflow to affect <img> and css backgrounds
571 if (toRenderSVGRoot(o)->isEmbeddedThroughSVGImage())
574 // FIXME: evaluate if we can allow overflow for these cases too.
575 // Overflow is always hidden when stand-alone SVG documents are embedded.
576 if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
582 bool ignoreOverflowHidden = false;
583 if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame())
584 ignoreOverflowHidden = true;
588 if (!ignoreOverflowHidden)
589 hMode = ScrollbarAlwaysOff;
592 hMode = ScrollbarAlwaysOn;
595 hMode = ScrollbarAuto;
598 // Don't set it at all.
604 if (!ignoreOverflowHidden)
605 vMode = ScrollbarAlwaysOff;
608 vMode = ScrollbarAlwaysOn;
611 vMode = ScrollbarAuto;
614 // Don't set it at all.
618 m_viewportRenderer = o;
621 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
623 m_viewportRenderer = 0;
625 // FIXME: How do we handle this for OOPI?
626 const HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
627 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
628 hMode = ScrollbarAlwaysOff;
629 vMode = ScrollbarAlwaysOff;
633 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
634 hMode = ScrollbarAuto;
635 vMode = ScrollbarAuto;
637 hMode = ScrollbarAlwaysOff;
638 vMode = ScrollbarAlwaysOff;
641 if (!isSubtreeLayout()) {
642 Document* document = m_frame->document();
643 Node* body = document->body();
644 if (isHTMLFrameSetElement(body) && body->renderer()) {
645 vMode = ScrollbarAlwaysOff;
646 hMode = ScrollbarAlwaysOff;
647 } else if (Element* viewportElement = document->viewportDefiningElement()) {
648 if (RenderObject* viewportRenderer = viewportElement->renderer()) {
649 if (viewportRenderer->style())
650 applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode);
656 void FrameView::updateAcceleratedCompositingSettings()
658 if (RenderView* renderView = this->renderView())
659 renderView->compositor()->updateAcceleratedCompositingSettings();
662 void FrameView::recalcOverflowAfterStyleChange()
664 RenderView* renderView = this->renderView();
665 RELEASE_ASSERT(renderView);
666 if (!renderView->needsOverflowRecalcAfterStyleChange())
669 renderView->recalcOverflowAfterStyleChange();
671 IntRect documentRect = renderView->documentRect();
672 if (scrollOrigin() == -documentRect.location() && contentsSize() == documentRect.size())
678 InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
680 bool shouldHaveHorizontalScrollbar = false;
681 bool shouldHaveVerticalScrollbar = false;
682 computeScrollbarExistence(shouldHaveHorizontalScrollbar, shouldHaveVerticalScrollbar, documentRect.size());
684 bool hasHorizontalScrollbar = horizontalScrollbar();
685 bool hasVerticalScrollbar = verticalScrollbar();
686 if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar
687 || hasVerticalScrollbar != shouldHaveVerticalScrollbar) {
693 updateScrollbarGeometry();
696 bool FrameView::usesCompositedScrolling() const
698 RenderView* renderView = this->renderView();
701 if (m_frame->settings() && m_frame->settings()->preferCompositingToLCDTextEnabled())
702 return renderView->compositor()->inCompositingMode();
706 GraphicsLayer* FrameView::layerForScrolling() const
708 RenderView* renderView = this->renderView();
711 return renderView->compositor()->scrollLayer();
714 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
716 RenderView* renderView = this->renderView();
719 return renderView->compositor()->layerForHorizontalScrollbar();
722 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
724 RenderView* renderView = this->renderView();
727 return renderView->compositor()->layerForVerticalScrollbar();
730 GraphicsLayer* FrameView::layerForScrollCorner() const
732 RenderView* renderView = this->renderView();
735 return renderView->compositor()->layerForScrollCorner();
738 bool FrameView::isEnclosedInCompositingLayer() const
740 // FIXME: It's a bug that compositing state isn't always up to date when this is called. crbug.com/366314
741 DisableCompositingQueryAsserts disabler;
743 RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
744 return frameOwnerRenderer && frameOwnerRenderer->enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
747 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
749 return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
752 inline void FrameView::forceLayoutParentViewIfNeeded()
754 RenderPart* ownerRenderer = m_frame->ownerRenderer();
755 if (!ownerRenderer || !ownerRenderer->frame())
758 RenderBox* contentBox = embeddedContentBox();
762 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
763 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
766 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
767 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
768 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
769 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
770 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
771 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
772 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
773 RefPtrWillBeRawPtr<FrameView> frameView = ownerRenderer->frame()->view();
775 // Mark the owner renderer as needing layout.
776 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
778 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
783 void FrameView::performPreLayoutTasks()
785 TRACE_EVENT0("blink", "FrameView::performPreLayoutTasks");
786 lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
788 // Don't schedule more layouts, we're in one.
789 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
791 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
792 // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
793 m_inSynchronousPostLayout = true;
794 performPostLayoutTasks();
795 m_inSynchronousPostLayout = false;
798 Document* document = m_frame->document();
799 if (wasViewportResized())
800 document->notifyResizeForViewportUnits();
802 // Viewport-dependent media queries may cause us to need completely different style information.
803 if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) {
804 document->styleResolverChanged();
805 document->mediaQueryAffectingValueChanged();
807 // FIXME: This instrumentation event is not strictly accurate since cached media query results
808 // do not persist across StyleResolver rebuilds.
809 InspectorInstrumentation::mediaQueryResultChanged(document);
811 document->evaluateMediaQueryList();
814 document->updateRenderTreeIfNeeded();
815 lifecycle().advanceTo(DocumentLifecycle::StyleClean);
818 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
820 TRACE_EVENT0("blink", "FrameView::performLayout");
822 ScriptForbiddenScope forbidScript;
824 ASSERT(!isInPerformLayout());
825 lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
827 TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
829 // performLayout is the actual guts of layout().
830 // FIXME: The 300 other lines in layout() probably belong in other helper functions
831 // so that a single human could understand what layout() is actually doing.
833 LayoutState layoutState(*rootForThisLayout);
835 forceLayoutParentViewIfNeeded();
837 // FIXME (crbug.com/256657): Do not do two layouts for text autosizing.
838 rootForThisLayout->layout();
839 gatherDebugLayoutRects(rootForThisLayout);
841 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
843 lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
846 void FrameView::scheduleOrPerformPostLayoutTasks()
848 if (m_postLayoutTasksTimer.isActive())
851 if (!m_inSynchronousPostLayout) {
852 m_inSynchronousPostLayout = true;
853 // Calls resumeScheduledEvents()
854 performPostLayoutTasks();
855 m_inSynchronousPostLayout = false;
858 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
859 // If we need layout or are already in a synchronous call to postLayoutTasks(),
860 // defer widget updates and event dispatch until after we return. postLayoutTasks()
861 // can make us need to update again, and we can get stuck in a nasty cycle unless
862 // we call it through the timer here.
863 m_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
869 void FrameView::layout(bool allowSubtree)
871 // We should never layout a Document which is not in a LocalFrame.
873 ASSERT(m_frame->view() == this);
874 ASSERT(m_frame->page());
876 ScriptForbiddenScope forbidScript;
878 if (isInPerformLayout() || !m_frame->document()->isActive())
881 TRACE_EVENT0("blink", "FrameView::layout");
882 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout");
884 // Protect the view from being deleted during layout (in recalcStyle)
885 RefPtrWillBeRawPtr<FrameView> protector(this);
887 // Every scroll that happens during layout is programmatic.
888 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
891 m_autoSizeInfo->autoSizeIfNeeded();
893 m_hasPendingLayout = false;
894 DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
896 RELEASE_ASSERT(!isPainting());
898 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "beginData", InspectorLayoutEvent::beginData(this));
899 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
900 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
901 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
903 if (!allowSubtree && isSubtreeLayout()) {
904 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
905 m_layoutSubtreeRoot = 0;
908 performPreLayoutTasks();
911 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
912 // so there's no point to continuing to layout
913 if (protector->hasOneRef())
917 Document* document = m_frame->document();
918 bool inSubtreeLayout = isSubtreeLayout();
919 RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView();
920 if (!rootForThisLayout) {
921 // FIXME: Do we need to set m_size here?
922 ASSERT_NOT_REACHED();
926 FontCachePurgePreventer fontCachePurgePreventer;
929 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
931 m_nestedLayoutCount++;
932 if (!inSubtreeLayout) {
933 Document* document = m_frame->document();
934 Node* body = document->body();
935 if (body && body->renderer()) {
936 if (isHTMLFrameSetElement(*body)) {
937 body->renderer()->setChildNeedsLayout();
938 } else if (isHTMLBodyElement(*body)) {
939 if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport())
940 body->renderer()->setChildNeedsLayout();
948 calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode);
950 if (!inSubtreeLayout) {
951 // Now set our scrollbar state for the layout.
952 ScrollbarMode currentHMode = horizontalScrollbarMode();
953 ScrollbarMode currentVMode = verticalScrollbarMode();
956 setScrollbarsSuppressed(true);
958 m_doFullPaintInvalidation = true;
959 m_firstLayout = false;
960 m_firstLayoutCallbackPending = true;
961 m_lastViewportSize = layoutSize(IncludeScrollbars);
962 m_lastZoomFactor = rootForThisLayout->style()->zoom();
964 // Set the initial vMode to AlwaysOn if we're auto.
965 if (vMode == ScrollbarAuto)
966 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
967 // Set the initial hMode to AlwaysOff if we're auto.
968 if (hMode == ScrollbarAuto)
969 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
971 setScrollbarModes(hMode, vMode);
972 setScrollbarsSuppressed(false, true);
973 } else if (hMode != currentHMode || vMode != currentVMode) {
974 setScrollbarModes(hMode, vMode);
977 LayoutSize oldSize = m_size;
979 m_size = LayoutSize(layoutSize().width(), layoutSize().height());
981 if (oldSize != m_size && !m_firstLayout) {
982 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
983 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
984 if (bodyRenderer && bodyRenderer->stretchesToViewport())
985 bodyRenderer->setChildNeedsLayout();
986 else if (rootRenderer && rootRenderer->stretchesToViewport())
987 rootRenderer->setChildNeedsLayout();
990 // We need to set m_doFullPaintInvalidation before triggering layout as RenderObject::checkForPaintInvalidation
991 // checks the boolean to disable local paint invalidations.
992 m_doFullPaintInvalidation |= renderView()->shouldDoFullPaintInvalidationForNextLayout();
995 layer = rootForThisLayout->enclosingLayer();
997 performLayout(rootForThisLayout, inSubtreeLayout);
999 m_layoutSubtreeRoot = 0;
1000 // We need to ensure that we mark up all renderers up to the RenderView
1001 // for paint invalidation. This simplifies our code as we just always
1002 // do a full tree walk.
1003 if (RenderObject* container = rootForThisLayout->container())
1004 container->setMayNeedPaintInvalidation(true);
1005 } // Reset m_layoutSchedulingEnabled to its previous value.
1007 if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing())
1010 layer->updateLayerPositionsAfterLayout();
1012 renderView()->compositor()->didLayout();
1016 if (AXObjectCache* cache = rootForThisLayout->document().axObjectCache()) {
1017 const KURL& url = rootForThisLayout->document().url();
1018 if (url.isValid() && !url.isAboutBlankURL())
1019 cache->handleLayoutComplete(rootForThisLayout);
1021 updateAnnotatedRegions();
1023 ASSERT(!rootForThisLayout->needsLayout());
1025 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1026 updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
1028 scheduleOrPerformPostLayoutTasks();
1030 TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout));
1031 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1032 InspectorInstrumentation::didLayout(cookie, rootForThisLayout);
1034 m_nestedLayoutCount--;
1035 if (m_nestedLayoutCount)
1039 // Post-layout assert that nobody was re-marked as needing layout during layout.
1040 document->renderView()->assertSubtreeIsLaidOut();
1043 // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
1044 // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
1045 // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from
1046 // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
1047 // necessitating this check here.
1048 // ASSERT(frame()->page());
1050 frame().page()->chrome().client().layoutUpdated(m_frame.get());
1053 // The plan is to move to compositor-queried paint invalidation, in which case this
1054 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
1055 // let the compositor pick which to actually draw.
1056 // See http://crbug.com/306706
1057 void FrameView::invalidateTreeIfNeeded()
1059 ASSERT(renderView());
1060 RenderView& rootForPaintInvalidation = *renderView();
1061 ASSERT(!rootForPaintInvalidation.needsLayout());
1063 TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation.debugName().ascii());
1065 PaintInvalidationState rootPaintInvalidationState(rootForPaintInvalidation);
1067 if (m_doFullPaintInvalidation)
1068 renderView()->compositor()->fullyInvalidatePaint();
1070 rootForPaintInvalidation.invalidateTreeIfNeeded(rootPaintInvalidationState);
1072 // Invalidate the paint of the frameviews scrollbars if needed
1073 if (hasVerticalBarDamage())
1074 invalidateRect(verticalBarDamage());
1075 if (hasHorizontalBarDamage())
1076 invalidateRect(horizontalBarDamage());
1077 resetScrollbarDamage();
1081 renderView()->assertSubtreeClearedPaintInvalidationState();
1084 if (m_frame->selection().isCaretBoundsDirty())
1085 m_frame->selection().invalidateCaretRect();
1088 DocumentLifecycle& FrameView::lifecycle() const
1090 return m_frame->document()->lifecycle();
1093 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot)
1096 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
1099 if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
1101 // For access to compositedLayerMapping().
1102 DisableCompositingQueryAsserts disabler;
1103 GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
1107 GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
1109 debugInfo.currentLayoutRects().clear();
1110 for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
1111 if (renderer->layoutDidGetCalledSinceLastFrame()) {
1112 FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect()));
1113 LayoutRect rect = quad.enclosingBoundingBox();
1114 debugInfo.currentLayoutRects().append(rect);
1119 RenderBox* FrameView::embeddedContentBox() const
1121 RenderView* renderView = this->renderView();
1125 RenderObject* firstChild = renderView->firstChild();
1126 if (!firstChild || !firstChild->isBox())
1129 // Curently only embedded SVG documents participate in the size-negotiation logic.
1130 if (firstChild->isSVGRoot())
1131 return toRenderBox(firstChild);
1137 void FrameView::addPart(RenderPart* object)
1139 m_parts.add(object);
1142 void FrameView::removePart(RenderPart* object)
1144 m_parts.remove(object);
1147 void FrameView::updateWidgetPositions()
1149 WillBeHeapVector<RefPtrWillBeMember<RenderPart> > parts;
1150 copyToVector(m_parts, parts);
1152 // Script or plugins could detach the frame so abort processing if that happens.
1154 for (size_t i = 0; i < parts.size() && renderView(); ++i)
1155 parts[i]->updateWidgetPosition();
1157 for (size_t i = 0; i < parts.size() && renderView(); ++i)
1158 parts[i]->widgetPositionsUpdated();
1161 void FrameView::addPartToUpdate(RenderEmbeddedObject& object)
1163 ASSERT(isInPerformLayout());
1164 // Tell the DOM element that it needs a widget update.
1165 Node* node = object.node();
1167 if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node))
1168 toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1170 m_partUpdateSet.add(&object);
1173 void FrameView::setMediaType(const AtomicString& mediaType)
1175 ASSERT(m_frame->document());
1176 m_frame->document()->mediaQueryAffectingValueChanged();
1177 m_mediaType = mediaType;
1180 AtomicString FrameView::mediaType() const
1182 // See if we have an override type.
1183 String overrideType;
1184 InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType);
1185 if (!overrideType.isNull())
1186 return AtomicString(overrideType);
1190 void FrameView::adjustMediaTypeForPrinting(bool printing)
1193 if (m_mediaTypeWhenNotPrinting.isNull())
1194 m_mediaTypeWhenNotPrinting = mediaType();
1195 setMediaType(MediaTypeNames::print);
1197 if (!m_mediaTypeWhenNotPrinting.isNull())
1198 setMediaType(m_mediaTypeWhenNotPrinting);
1199 m_mediaTypeWhenNotPrinting = nullAtom;
1203 bool FrameView::contentsInCompositedLayer() const
1205 RenderView* renderView = this->renderView();
1206 if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) {
1207 GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer();
1208 if (layer && layer->drawsContent())
1215 void FrameView::addSlowRepaintObject()
1217 if (!m_slowRepaintObjectCount++) {
1218 if (Page* page = m_frame->page()) {
1219 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1220 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1225 void FrameView::removeSlowRepaintObject()
1227 ASSERT(m_slowRepaintObjectCount > 0);
1228 m_slowRepaintObjectCount--;
1229 if (!m_slowRepaintObjectCount) {
1230 if (Page* page = m_frame->page()) {
1231 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1232 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1237 void FrameView::addViewportConstrainedObject(RenderObject* object)
1239 if (!m_viewportConstrainedObjects)
1240 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1242 if (!m_viewportConstrainedObjects->contains(object)) {
1243 m_viewportConstrainedObjects->add(object);
1245 if (Page* page = m_frame->page()) {
1246 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1247 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1252 void FrameView::removeViewportConstrainedObject(RenderObject* object)
1254 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1255 m_viewportConstrainedObjects->remove(object);
1257 if (Page* page = m_frame->page()) {
1258 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1259 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1264 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1266 LayoutRect viewportRect = visibleContentRect();
1267 // Ignore overhang. No-op when not using rubber banding.
1268 viewportRect.setLocation(clampScrollPosition(scrollPosition()));
1269 return viewportRect;
1272 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged)
1274 if (!hasViewportConstrainedObjects())
1277 // If viewport is not enabled, frameRect change will cause layout size change and then layout.
1278 // Otherwise, viewport constrained objects need their layout flags set separately to ensure
1279 // they are positioned correctly. In the virtual-viewport pinch mode frame rect changes wont
1280 // necessarily cause a layout size change so only take this early-out if we're in old-style
1282 if (m_frame->settings()
1283 && !m_frame->settings()->viewportEnabled()
1284 && !m_frame->settings()->pinchVirtualViewportEnabled())
1287 for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
1288 RenderObject* renderer = viewportConstrainedObject;
1289 RenderStyle* style = renderer->style();
1291 if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto()))
1292 renderer->setNeedsPositionedMovementLayout();
1294 renderer->setNeedsLayoutAndFullPaintInvalidation();
1296 if (heightChanged) {
1297 if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto()))
1298 renderer->setNeedsPositionedMovementLayout();
1300 renderer->setNeedsLayoutAndFullPaintInvalidation();
1305 IntSize FrameView::scrollOffsetForFixedPosition() const
1307 return toIntSize(clampScrollPosition(scrollPosition()));
1310 IntPoint FrameView::lastKnownMousePosition() const
1312 return m_frame->eventHandler().lastKnownMousePosition();
1315 bool FrameView::shouldSetCursor() const
1317 Page* page = frame().page();
1318 return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive() && page->settings().deviceSupportsMouse();
1321 void FrameView::scrollContentsIfNeededRecursive()
1323 scrollContentsIfNeeded();
1325 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1326 if (!child->isLocalFrame())
1328 if (FrameView* view = toLocalFrame(child)->view())
1329 view->scrollContentsIfNeededRecursive();
1333 // FIXME: If we had a flag to force invalidations in a whole subtree, we could get rid of this function (crbug.com/410097).
1334 static void setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(const RenderLayer* layer)
1336 layer->renderer()->setShouldDoFullPaintInvalidation();
1338 for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) {
1339 // Don't include paint invalidation rects for composited child layers; they will paint themselves and have a different origin.
1340 if (child->isPaintInvalidationContainer())
1343 setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(child);
1347 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
1349 if (!contentsInCompositedLayer() || hasSlowRepaintObjects())
1352 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1353 InspectorInstrumentation::didScroll(page());
1357 for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
1358 RenderObject* renderer = viewportConstrainedObject;
1359 ASSERT(renderer->style()->hasViewportConstrainedPosition());
1360 ASSERT(renderer->hasLayer());
1361 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1363 if (layer->isPaintInvalidationContainer())
1366 if (layer->subtreeIsInvisible())
1369 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1370 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1371 if (layer->hasAncestorWithFilterOutsets())
1374 setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(layer);
1377 InspectorInstrumentation::didScroll(page());
1381 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1383 if (contentsInCompositedLayer()) {
1384 IntRect updateRect = visibleContentRect();
1385 ASSERT(renderView());
1386 renderView()->invalidatePaintRectangle(updateRect);
1388 if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
1389 if (isEnclosedInCompositingLayer()) {
1390 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1391 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1392 visibleWidth(), visibleHeight());
1393 frameRenderer->invalidatePaintRectangle(rect);
1398 hostWindow()->invalidateContentsForSlowScroll(updateRect);
1401 void FrameView::restoreScrollbar()
1403 setScrollbarsSuppressed(false);
1406 bool FrameView::scrollToFragment(const KURL& url)
1408 // If our URL has no ref, then we have no place we need to jump to.
1409 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1410 // and possibly paint invalidation because :target pseudo class may have been
1411 // set (see bug 11321).
1412 if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1415 String fragmentIdentifier = url.fragmentIdentifier();
1416 if (scrollToAnchor(fragmentIdentifier))
1419 // Try again after decoding the ref, based on the document's encoding.
1420 if (m_frame->document()->encoding().isValid())
1421 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()));
1426 bool FrameView::scrollToAnchor(const String& name)
1428 ASSERT(m_frame->document());
1430 if (!m_frame->document()->isRenderingReady()) {
1431 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1435 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1437 Element* anchorNode = m_frame->document()->findAnchor(name);
1439 // Setting to null will clear the current target.
1440 m_frame->document()->setCSSTarget(anchorNode);
1442 if (m_frame->document()->isSVGDocument()) {
1443 if (SVGSVGElement* svg = SVGDocumentExtensions::rootElement(*m_frame->document())) {
1444 svg->setupInitialView(name, anchorNode);
1450 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1451 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1454 maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1456 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1457 // If anchorNode is not focusable, setFocusedElement() will still clear focus, which matches the behavior of other browsers.
1459 m_frame->document()->setFocusedElement(anchorNode);
1464 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1466 m_maintainScrollPositionAnchor = anchorNode;
1467 if (!m_maintainScrollPositionAnchor)
1470 // We need to update the layout before scrolling, otherwise we could
1471 // really mess things up if an anchor scroll comes at a bad moment.
1472 m_frame->document()->updateRenderTreeIfNeeded();
1473 // Only do a layout if changes have occurred that make it necessary.
1474 RenderView* renderView = this->renderView();
1475 if (renderView && renderView->needsLayout())
1481 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1483 // FIXME(http://crbug.com/371896) - This method shouldn't be manually doing
1484 // coordinate transformations to the PinchViewport.
1485 IntRect targetRect(rect);
1487 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1489 bool pinchVirtualViewportEnabled = m_frame->settings()->pinchVirtualViewportEnabled();
1491 if (pinchVirtualViewportEnabled) {
1492 PinchViewport& pinchViewport = m_frame->page()->frameHost().pinchViewport();
1494 IntSize pinchViewportSize = expandedIntSize(pinchViewport.visibleRect().size());
1495 targetRect.moveBy(ceiledIntPoint(pinchViewport.visibleRect().location()));
1496 targetRect.setSize(pinchViewportSize.shrunkTo(targetRect.size()));
1499 LayoutRect bounds = element->boundingBox();
1500 int centeringOffsetX = (targetRect.width() - bounds.width()) / 2;
1501 int centeringOffsetY = (targetRect.height() - bounds.height()) / 2;
1503 IntPoint targetOffset(
1504 bounds.x() - centeringOffsetX - targetRect.x(),
1505 bounds.y() - centeringOffsetY - targetRect.y());
1507 setScrollPosition(DoublePoint(targetOffset));
1509 if (pinchVirtualViewportEnabled) {
1510 IntPoint remainder = IntPoint(targetOffset - scrollPosition());
1511 m_frame->page()->frameHost().pinchViewport().move(remainder);
1515 void FrameView::setScrollPosition(const DoublePoint& scrollPoint, ScrollBehavior scrollBehavior)
1517 cancelProgrammaticScrollAnimation();
1518 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1519 m_maintainScrollPositionAnchor = nullptr;
1521 DoublePoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1522 if (newScrollPosition == scrollPositionDouble())
1525 if (scrollBehavior == ScrollBehaviorAuto) {
1526 RenderObject* renderer = m_frame->document()->documentElement() ? m_frame->document()->documentElement()->renderer() : 0;
1528 scrollBehavior = renderer->style()->scrollBehavior();
1530 scrollBehavior = ScrollBehaviorInstant;
1533 if (scrollBehavior == ScrollBehaviorInstant) {
1534 DoubleSize newOffset(newScrollPosition.x(), newScrollPosition.y());
1535 updateScrollbars(newOffset);
1537 programmaticallyScrollSmoothlyToOffset(toFloatPoint(newScrollPosition));
1541 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint)
1543 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1545 if (newScrollPosition == scrollPosition())
1548 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false);
1549 notifyScrollPositionChanged(newScrollPosition);
1552 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1554 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1557 void FrameView::setLayoutSize(const IntSize& size)
1559 ASSERT(!layoutSizeFixedToFrameSize());
1561 setLayoutSizeInternal(size);
1564 void FrameView::scrollPositionChanged()
1566 setWasScrolledByUser(true);
1568 Document* document = m_frame->document();
1569 document->enqueueScrollEventForNode(document);
1571 m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1573 if (RenderView* renderView = document->renderView()) {
1574 if (renderView->usesCompositing())
1575 renderView->compositor()->frameViewDidScroll();
1578 if (m_didScrollTimer.isActive())
1579 m_didScrollTimer.stop();
1580 m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE);
1582 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1583 cache->handleScrollPositionChanged(this);
1585 frame().loader().saveScrollState();
1588 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1590 if (m_frame->document() && m_frame->document()->renderView()) {
1591 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1595 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
1597 // Nothing to do after scrolling if there are no fixed position elements.
1598 if (!hasViewportConstrainedObjects())
1601 RefPtrWillBeRawPtr<FrameView> protect(this);
1603 // If there fixed position elements, scrolling may cause compositing layers to change.
1604 // Update widget and layer positions after scrolling, but only if we're not inside of
1606 if (!m_nestedLayoutCount) {
1607 updateWidgetPositions();
1608 if (RenderView* renderView = this->renderView())
1609 renderView->layer()->setNeedsCompositingInputsUpdate();
1613 bool FrameView::computeCompositedSelectionBounds(LocalFrame& frame, CompositedSelectionBound& start, CompositedSelectionBound& end)
1615 const VisibleSelection &selection = frame.selection().selection();
1616 if (!selection.isCaretOrRange())
1619 VisiblePosition visibleStart(selection.visibleStart());
1620 VisiblePosition visibleEnd(selection.visibleEnd());
1622 RenderedPosition renderedStart(visibleStart);
1623 RenderedPosition renderedEnd(visibleEnd);
1625 renderedStart.positionInGraphicsLayerBacking(start);
1629 renderedEnd.positionInGraphicsLayerBacking(end);
1633 if (selection.isCaret()) {
1634 start.type = end.type = CompositedSelectionBound::Caret;
1638 TextDirection startDir = visibleStart.deepEquivalent().primaryDirection();
1639 TextDirection endDir = visibleEnd.deepEquivalent().primaryDirection();
1640 start.type = startDir == RTL ? CompositedSelectionBound::SelectionRight : CompositedSelectionBound::SelectionLeft;
1641 end.type = endDir == RTL ? CompositedSelectionBound::SelectionLeft : CompositedSelectionBound::SelectionRight;
1645 void FrameView::updateCompositedSelectionBoundsIfNeeded()
1647 if (!RuntimeEnabledFeatures::compositedSelectionUpdateEnabled())
1650 Page* page = frame().page();
1653 CompositedSelectionBound start, end;
1654 LocalFrame* frame = toLocalFrame(page->focusController().focusedOrMainFrame());
1655 if (!frame || !computeCompositedSelectionBounds(*frame, start, end)) {
1656 page->chrome().client().clearCompositedSelectionBounds();
1660 page->chrome().client().updateCompositedSelectionBounds(start, end);
1663 bool FrameView::isRubberBandInProgress() const
1665 if (scrollbarsSuppressed())
1668 // If the main thread updates the scroll position for this FrameView, we should return
1669 // ScrollAnimator::isRubberBandInProgress().
1670 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1671 return scrollAnimator->isRubberBandInProgress();
1676 HostWindow* FrameView::hostWindow() const
1678 Page* page = frame().page();
1681 return &page->chrome();
1684 void FrameView::contentRectangleForPaintInvalidation(const IntRect& rect)
1686 ASSERT(paintInvalidationIsAllowed());
1687 ASSERT(!m_frame->ownerRenderer());
1689 if (m_isTrackingPaintInvalidations) {
1690 IntRect paintInvalidationRect = rect;
1691 paintInvalidationRect.move(-scrollOffset());
1692 m_trackedPaintInvalidationRects.append(paintInvalidationRect);
1693 // FIXME: http://crbug.com/368518. Eventually, invalidateContentRectangleForPaint
1694 // is going away entirely once all layout tests are FCM. In the short
1695 // term, no code should be tracking non-composited FrameView paint invalidations.
1696 RELEASE_ASSERT_NOT_REACHED();
1699 IntRect paintRect = rect;
1700 if (clipsPaintInvalidations())
1701 paintRect.intersect(visibleContentRect());
1702 if (paintRect.isEmpty())
1705 if (HostWindow* window = hostWindow())
1706 window->invalidateContentsAndRootView(contentsToWindow(paintRect));
1709 void FrameView::contentsResized()
1711 if (m_frame->isMainFrame() && m_frame->document()) {
1712 if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
1713 textAutosizer->updatePageInfoInAllFrames();
1716 ScrollableArea::contentsResized();
1720 void FrameView::scrollbarExistenceDidChange()
1722 // We check to make sure the view is attached to a frame() as this method can
1723 // be triggered before the view is attached by LocalFrame::createView(...) setting
1724 // various values such as setScrollBarModes(...) for example. An ASSERT is
1725 // triggered when a view is layout before being attached to a frame().
1726 if (!frame().view())
1729 // Note that simply having overlay scrollbars is not sufficient to be
1730 // certain that scrollbars' presence does not impact layout. This should
1731 // also check if custom scrollbars (as reported by shouldUseCustomScrollbars)
1732 // are in use as well.
1733 // http://crbug.com/269692
1734 bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars();
1736 // FIXME: this call to layout() could be called within FrameView::layout(), but before performLayout(),
1737 // causing double-layout. See also crbug.com/429242.
1738 if (!useOverlayScrollbars && needsLayout())
1741 if (renderView() && renderView()->usesCompositing()) {
1742 renderView()->compositor()->frameViewScrollbarsExistenceDidChange();
1744 if (!useOverlayScrollbars)
1745 renderView()->compositor()->frameViewDidChangeSize();
1749 void FrameView::handleLoadCompleted()
1751 // Once loading has completed, allow autoSize one last opportunity to
1752 // reduce the size of the frame.
1754 m_autoSizeInfo->autoSizeIfNeeded();
1757 void FrameView::scheduleRelayout()
1759 ASSERT(m_frame->view() == this);
1761 if (isSubtreeLayout()) {
1762 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1763 m_layoutSubtreeRoot = 0;
1765 if (!m_layoutSchedulingEnabled)
1769 if (!m_frame->document()->shouldScheduleLayout())
1771 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1772 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1773 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1774 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1776 if (m_hasPendingLayout)
1778 m_hasPendingLayout = true;
1780 page()->animator().scheduleVisualUpdate();
1781 lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1784 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1786 for (RenderObject* r = descendant; r; r = r->container()) {
1793 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1795 ASSERT(m_frame->view() == this);
1797 // FIXME: Should this call shouldScheduleLayout instead?
1798 if (!m_frame->document()->isActive())
1801 RenderView* renderView = this->renderView();
1802 if (renderView && renderView->needsLayout()) {
1804 relayoutRoot->markContainingBlocksForLayout(false);
1808 if (layoutPending() || !m_layoutSchedulingEnabled) {
1809 if (m_layoutSubtreeRoot != relayoutRoot) {
1810 if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
1811 // Keep the current root
1812 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
1813 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1814 } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
1815 // Re-root at relayoutRoot
1816 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
1817 m_layoutSubtreeRoot = relayoutRoot;
1818 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1820 // Just do a full relayout
1821 if (isSubtreeLayout())
1822 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1823 m_layoutSubtreeRoot = 0;
1824 relayoutRoot->markContainingBlocksForLayout(false);
1827 } else if (m_layoutSchedulingEnabled) {
1828 m_layoutSubtreeRoot = relayoutRoot;
1829 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1830 m_hasPendingLayout = true;
1832 page()->animator().scheduleVisualUpdate();
1833 lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1835 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1836 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1837 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1838 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1841 bool FrameView::layoutPending() const
1843 // FIXME: This should check Document::lifecycle instead.
1844 return m_hasPendingLayout;
1847 bool FrameView::isInPerformLayout() const
1849 ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1850 return m_inPerformLayout;
1853 bool FrameView::needsLayout() const
1855 // This can return true in cases where the document does not have a body yet.
1856 // Document::shouldScheduleLayout takes care of preventing us from scheduling
1857 // layout in that case.
1859 RenderView* renderView = this->renderView();
1860 return layoutPending()
1861 || (renderView && renderView->needsLayout())
1862 || isSubtreeLayout();
1865 void FrameView::setNeedsLayout()
1867 if (RenderView* renderView = this->renderView())
1868 renderView->setNeedsLayout();
1871 bool FrameView::isTransparent() const
1873 return m_isTransparent;
1876 void FrameView::setTransparent(bool isTransparent)
1878 m_isTransparent = isTransparent;
1879 DisableCompositingQueryAsserts disabler;
1880 if (renderView() && renderView()->layer()->hasCompositedLayerMapping())
1881 renderView()->layer()->compositedLayerMapping()->updateContentsOpaque();
1884 bool FrameView::hasOpaqueBackground() const
1886 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1889 Color FrameView::baseBackgroundColor() const
1891 return m_baseBackgroundColor;
1894 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1896 m_baseBackgroundColor = backgroundColor;
1898 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) {
1899 CompositedLayerMapping* compositedLayerMapping = renderView()->layer()->compositedLayerMapping();
1900 compositedLayerMapping->updateContentsOpaque();
1901 if (compositedLayerMapping->mainGraphicsLayer())
1902 compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1904 recalculateScrollbarOverlayStyle();
1907 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1909 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1910 if (!frame->isLocalFrame())
1912 if (FrameView* view = toLocalFrame(frame)->view()) {
1913 view->setTransparent(transparent);
1914 view->setBaseBackgroundColor(backgroundColor);
1919 void FrameView::scrollToAnchor()
1921 RefPtrWillBeRawPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1925 if (!anchorNode->renderer())
1929 if (anchorNode != m_frame->document())
1930 rect = anchorNode->boundingBox();
1932 RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = m_frame->document()->findUnsafeParentScrollPropagationBoundary();
1935 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1937 // Scroll nested layers and frames to reveal the anchor.
1938 // Align to the top and to the closest side (this matches other browsers).
1939 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1942 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1944 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1945 cache->handleScrolledToAnchor(anchorNode.get());
1947 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
1948 m_maintainScrollPositionAnchor = anchorNode;
1951 bool FrameView::updateWidgets()
1953 // This is always called from updateWidgetsTimerFired.
1954 // m_updateWidgetsTimer should only be scheduled if we have widgets to update.
1955 // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty:
1956 // FIXME: This assert has been temporarily removed due to https://crbug.com/430344
1957 if (m_nestedLayoutCount > 1 || m_partUpdateSet.isEmpty())
1960 // Need to swap because script will run inside the below loop and invalidate the iterator.
1961 EmbeddedObjectSet objects;
1962 objects.swap(m_partUpdateSet);
1964 for (const auto& embeddedObject : objects) {
1965 RenderEmbeddedObject& object = *embeddedObject;
1966 HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
1968 // The object may have already been destroyed (thus node cleared),
1969 // but FrameView holds a manual ref, so it won't have been deleted.
1973 // No need to update if it's already crashed or known to be missing.
1974 if (object.showsUnavailablePluginIndicator())
1977 if (element->needsWidgetUpdate())
1978 element->updateWidget();
1979 object.updateWidgetPosition();
1981 // Prevent plugins from causing infinite updates of themselves.
1982 // FIXME: Do we really need to prevent this?
1983 m_partUpdateSet.remove(&object);
1986 return m_partUpdateSet.isEmpty();
1989 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
1991 ASSERT(!isInPerformLayout());
1992 RefPtrWillBeRawPtr<FrameView> protect(this);
1993 m_updateWidgetsTimer.stop();
1994 for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
1995 if (updateWidgets())
2000 void FrameView::flushAnyPendingPostLayoutTasks()
2002 ASSERT(!isInPerformLayout());
2003 if (m_postLayoutTasksTimer.isActive())
2004 performPostLayoutTasks();
2005 if (m_updateWidgetsTimer.isActive())
2006 updateWidgetsTimerFired(0);
2009 void FrameView::scheduleUpdateWidgetsIfNecessary()
2011 ASSERT(!isInPerformLayout());
2012 if (m_updateWidgetsTimer.isActive() || m_partUpdateSet.isEmpty())
2014 m_updateWidgetsTimer.startOneShot(0, FROM_HERE);
2017 void FrameView::performPostLayoutTasks()
2019 // FIXME: We can reach here, even when the page is not active!
2020 // http/tests/inspector/elements/html-link-import.html and many other
2021 // tests hit that case.
2022 // We should ASSERT(isActive()); or at least return early if we can!
2023 ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
2024 TRACE_EVENT0("blink", "FrameView::performPostLayoutTasks");
2025 RefPtrWillBeRawPtr<FrameView> protect(this);
2027 m_postLayoutTasksTimer.stop();
2029 m_frame->selection().setCaretRectNeedsUpdate();
2032 // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
2033 DisableCompositingQueryAsserts disabler;
2034 m_frame->selection().updateAppearance();
2037 ASSERT(m_frame->document());
2038 if (m_nestedLayoutCount <= 1) {
2039 if (m_firstLayoutCallbackPending)
2040 m_firstLayoutCallbackPending = false;
2042 // Ensure that we always send this eventually.
2043 if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad())
2044 m_isVisuallyNonEmpty = true;
2046 // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2047 if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2048 m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2049 // FIXME: This callback is probably not needed, but is currently used
2050 // by android for setting the background color.
2051 m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout();
2055 FontFaceSet::didLayout(*m_frame->document());
2057 updateWidgetPositions();
2059 // Plugins could have torn down the page inside updateWidgetPositions().
2063 scheduleUpdateWidgetsIfNecessary();
2065 if (Page* page = m_frame->page()) {
2066 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2067 scrollingCoordinator->notifyLayoutUpdated();
2072 sendResizeEventIfNeeded();
2075 bool FrameView::wasViewportResized()
2078 RenderView* renderView = this->renderView();
2081 ASSERT(renderView->style());
2082 return (layoutSize(IncludeScrollbars) != m_lastViewportSize || renderView->style()->zoom() != m_lastZoomFactor);
2085 void FrameView::sendResizeEventIfNeeded()
2089 RenderView* renderView = this->renderView();
2090 if (!renderView || renderView->document().printing())
2093 if (!wasViewportResized())
2096 m_lastViewportSize = layoutSize(IncludeScrollbars);
2097 m_lastZoomFactor = renderView->style()->zoom();
2099 m_frame->document()->enqueueResizeEvent();
2101 if (m_frame->isMainFrame())
2102 InspectorInstrumentation::didResizeMainFrame(m_frame->page());
2105 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2107 performPostLayoutTasks();
2110 void FrameView::updateCounters()
2112 RenderView* view = renderView();
2113 if (!view->hasRenderCounters())
2116 for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) {
2117 if (!renderer->isCounter())
2120 toRenderCounter(renderer)->updateCounter();
2124 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2126 if (!m_viewportRenderer)
2129 if (m_overflowStatusDirty) {
2130 m_horizontalOverflow = horizontalOverflow;
2131 m_verticalOverflow = verticalOverflow;
2132 m_overflowStatusDirty = false;
2136 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2137 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2139 if (horizontalOverflowChanged || verticalOverflowChanged) {
2140 m_horizontalOverflow = horizontalOverflow;
2141 m_verticalOverflow = verticalOverflow;
2143 RefPtrWillBeRawPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow);
2144 event->setTarget(m_viewportRenderer->node());
2145 m_frame->document()->enqueueAnimationFrameEvent(event.release());
2150 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const
2152 ASSERT(m_frame->view() == this);
2154 // Set our clip rect to be our contents.
2155 IntRect clipRect = contentsToWindow(visibleContentRect(scrollbarInclusion));
2156 if (!m_frame->deprecatedLocalOwner())
2159 // Take our owner element and get its clip rect.
2160 // FIXME: Do we need to do this for remote frames?
2161 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
2162 FrameView* parentView = ownerElement->document().view();
2164 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement));
2168 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement) const
2170 // The renderer can sometimes be null when style="display:none" interacts
2171 // with external content and plugins.
2172 if (!ownerElement->renderer())
2173 return windowClipRect();
2175 // If we have no layer, just return our window clip rect.
2176 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2177 if (!enclosingLayer)
2178 return windowClipRect();
2180 // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2181 // https://code.google.com/p/chromium/issues/detail?id=343769
2182 DisableCompositingQueryAsserts disabler;
2184 // Apply the clip from the layer.
2185 IntRect clipRect = contentsToWindow(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
2186 return intersection(clipRect, windowClipRect());
2189 bool FrameView::isActive() const
2191 Page* page = frame().page();
2192 return page && page->focusController().isActive();
2195 void FrameView::scrollTo(const DoublePoint& newPosition)
2197 DoublePoint oldPosition = m_scrollPosition;
2198 DoubleSize scrollDelta = newPosition - oldPosition;
2199 if (scrollDelta.isZero())
2202 if (m_frame->settings() && m_frame->settings()->rootLayerScrolls()) {
2203 // Don't scroll the FrameView!
2204 ASSERT_NOT_REACHED();
2207 m_scrollPosition = newPosition;
2209 if (!scrollbarsSuppressed())
2210 m_pendingScrollDelta += scrollDelta;
2212 updateLayersAndCompositingAfterScrollIfNeeded();
2213 scrollPositionChanged();
2214 frame().loader().client()->didChangeScrollOffset();
2217 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2219 // Add in our offset within the FrameView.
2220 IntRect dirtyRect = rect;
2221 dirtyRect.moveBy(scrollbar->location());
2223 if (isInPerformLayout())
2224 addScrollbarDamage(scrollbar, rect);
2226 invalidateRect(dirtyRect);
2229 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2231 if (!m_tickmarks.isEmpty())
2232 tickmarks = m_tickmarks;
2234 tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch);
2237 IntRect FrameView::windowResizerRect() const
2239 Page* page = frame().page();
2242 return page->chrome().windowResizerRect();
2245 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
2247 if (m_visibleContentScaleFactor == visibleContentScaleFactor)
2250 m_visibleContentScaleFactor = visibleContentScaleFactor;
2251 updateScrollbars(scrollOffsetDouble());
2254 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2256 m_inputEventsOffsetForEmulation = offset;
2257 m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2260 IntSize FrameView::inputEventsOffsetForEmulation() const
2262 return m_inputEventsOffsetForEmulation;
2265 float FrameView::inputEventsScaleFactor() const
2267 float pageScale = m_frame->settings()->pinchVirtualViewportEnabled()
2268 ? m_frame->page()->frameHost().pinchViewport().scale()
2269 : visibleContentScaleFactor();
2270 return pageScale * m_inputEventsScaleFactorForEmulation;
2273 bool FrameView::scrollbarsCanBeActive() const
2275 if (m_frame->view() != this)
2278 return !!m_frame->document();
2281 IntRect FrameView::scrollableAreaBoundingBox() const
2283 RenderPart* ownerRenderer = frame().ownerRenderer();
2287 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
2291 bool FrameView::isScrollable()
2293 return scrollingReasons() == Scrollable;
2296 FrameView::ScrollingReasons FrameView::scrollingReasons()
2299 // 1) If there an actual overflow.
2300 // 2) display:none or visibility:hidden set to self or inherited.
2301 // 3) overflow{-x,-y}: hidden;
2302 // 4) scrolling: no;
2305 IntSize contentsSize = this->contentsSize();
2306 IntSize visibleContentSize = visibleContentRect().size();
2307 if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2308 return NotScrollableNoOverflow;
2311 // FIXME: Do we need to fix this for OOPI?
2312 HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
2313 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
2314 return NotScrollableNotVisible;
2317 ScrollbarMode horizontalMode;
2318 ScrollbarMode verticalMode;
2319 calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly);
2320 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2321 return NotScrollableExplicitlyDisabled;
2326 void FrameView::updateScrollableAreaSet()
2328 // That ensures that only inner frames are cached.
2329 FrameView* parentFrameView = this->parentFrameView();
2330 if (!parentFrameView)
2333 if (!isScrollable()) {
2334 parentFrameView->removeScrollableArea(this);
2338 parentFrameView->addScrollableArea(this);
2341 bool FrameView::shouldSuspendScrollAnimations() const
2343 return m_frame->loader().state() != FrameStateComplete;
2346 void FrameView::scrollbarStyleChanged()
2348 // FIXME: Why does this only apply to the main frame?
2349 if (!m_frame->isMainFrame())
2351 adjustScrollbarOpacity();
2353 updateScrollbars(scrollOffsetDouble());
2354 positionScrollbarLayers();
2357 void FrameView::notifyPageThatContentAreaWillPaint() const
2359 Page* page = m_frame->page();
2363 contentAreaWillPaint();
2365 if (!m_scrollableAreas)
2368 for (const auto& scrollableArea : *m_scrollableAreas) {
2369 if (!scrollableArea->scrollbarsCanBeActive())
2372 scrollableArea->contentAreaWillPaint();
2376 bool FrameView::scrollAnimatorEnabled() const
2378 return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled();
2381 void FrameView::updateAnnotatedRegions()
2383 Document* document = m_frame->document();
2384 if (!document->hasAnnotatedRegions())
2386 Vector<AnnotatedRegionValue> newRegions;
2387 document->renderBox()->collectAnnotatedRegions(newRegions);
2388 if (newRegions == document->annotatedRegions())
2390 document->setAnnotatedRegions(newRegions);
2391 if (Page* page = m_frame->page())
2392 page->chrome().client().annotatedRegionsChanged();
2395 void FrameView::updateScrollCorner()
2397 RefPtr<RenderStyle> cornerStyle;
2398 IntRect cornerRect = scrollCornerRect();
2399 Document* doc = m_frame->document();
2401 if (doc && !cornerRect.isEmpty()) {
2402 // Try the <body> element first as a scroll corner source.
2403 if (Element* body = doc->body()) {
2404 if (RenderObject* renderer = body->renderer())
2405 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2409 // If the <body> didn't have a custom style, then the root element might.
2410 if (Element* docElement = doc->documentElement()) {
2411 if (RenderObject* renderer = docElement->renderer())
2412 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2417 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
2418 if (RenderPart* renderer = m_frame->ownerRenderer())
2419 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2424 if (!m_scrollCorner)
2425 m_scrollCorner = RenderScrollbarPart::createAnonymous(doc);
2426 m_scrollCorner->setStyle(cornerStyle.release());
2427 invalidateScrollCorner(cornerRect);
2428 } else if (m_scrollCorner) {
2429 m_scrollCorner->destroy();
2430 m_scrollCorner = nullptr;
2434 Color FrameView::documentBackgroundColor() const
2436 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2437 // the document and the body against the base background color of the frame view.
2438 // Background images are unfortunately impractical to include.
2440 Color result = baseBackgroundColor();
2441 if (!frame().document())
2444 Element* htmlElement = frame().document()->documentElement();
2445 Element* bodyElement = frame().document()->body();
2447 // We take the aggregate of the base background color
2448 // the <html> background color, and the <body>
2449 // background color to find the document color. The
2450 // addition of the base background color is not
2451 // technically part of the document background, but it
2452 // otherwise poses problems when the aggregate is not
2454 if (htmlElement && htmlElement->renderer())
2455 result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2456 if (bodyElement && bodyElement->renderer())
2457 result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2462 bool FrameView::hasCustomScrollbars() const
2464 const ChildrenWidgetSet* viewChildren = children();
2465 for (const RefPtrWillBeMember<Widget>& child : *viewChildren) {
2466 Widget* widget = child.get();
2467 if (widget->isFrameView()) {
2468 if (toFrameView(widget)->hasCustomScrollbars())
2470 } else if (widget->isScrollbar()) {
2471 if (toScrollbar(widget)->isCustomScrollbar())
2479 FrameView* FrameView::parentFrameView() const
2484 Frame* parentFrame = m_frame->tree().parent();
2485 if (parentFrame && parentFrame->isLocalFrame())
2486 return toLocalFrame(parentFrame)->view();
2491 bool FrameView::wasScrolledByUser() const
2493 return m_wasScrolledByUser;
2496 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
2498 if (m_inProgrammaticScroll)
2500 m_maintainScrollPositionAnchor = nullptr;
2501 m_wasScrolledByUser = wasScrolledByUser;
2504 void FrameView::setPaintBehavior(PaintBehavior behavior)
2506 m_paintBehavior = behavior;
2509 PaintBehavior FrameView::paintBehavior() const
2511 return m_paintBehavior;
2514 bool FrameView::isPainting() const
2516 return m_isPainting;
2519 void FrameView::setNodeToDraw(Node* node)
2521 m_nodeToDraw = node;
2524 void FrameView::updateWidgetPositionsIfNeeded()
2526 if (!m_needsUpdateWidgetPositions)
2529 m_needsUpdateWidgetPositions = false;
2531 updateWidgetPositions();
2534 void FrameView::updateLayoutAndStyleForPainting()
2536 // Updating layout can run script, which can tear down the FrameView.
2537 RefPtrWillBeRawPtr<FrameView> protector(this);
2539 updateLayoutAndStyleIfNeededRecursive();
2541 updateWidgetPositionsIfNeeded();
2543 RenderView* view = renderView();
2545 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateLayerTree", "frame", m_frame.get());
2546 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
2547 InspectorInstrumentation::willUpdateLayerTree(m_frame.get());
2549 view->compositor()->updateIfNeededRecursive();
2551 if (view->compositor()->inCompositingMode() && m_frame->isLocalRoot())
2552 m_frame->page()->scrollingCoordinator()->updateAfterCompositingChangeIfNeeded();
2554 updateCompositedSelectionBoundsIfNeeded();
2556 InspectorInstrumentation::didUpdateLayerTree(m_frame.get());
2559 scrollContentsIfNeededRecursive();
2562 invalidateTreeIfNeededRecursive();
2564 ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean);
2567 void FrameView::updateLayoutAndStyleIfNeededRecursive()
2569 // We have to crawl our entire tree looking for any FrameViews that need
2570 // layout and make sure they are up to date.
2571 // Mac actually tests for intersection with the dirty region and tries not to
2572 // update layout for frames that are outside the dirty region. Not only does this seem
2573 // pointless (since those frames will have set a zero timer to layout anyway), but
2574 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2575 // region but then become included later by the second frame adding rects to the dirty region
2576 // when it lays out.
2578 m_frame->document()->updateRenderTreeIfNeeded();
2583 // FIXME: Calling layout() shouldn't trigger scripe execution or have any
2584 // observable effects on the frame tree but we're not quite there yet.
2585 WillBeHeapVector<RefPtrWillBeMember<FrameView> > frameViews;
2586 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2587 if (!child->isLocalFrame())
2589 if (FrameView* view = toLocalFrame(child)->view())
2590 frameViews.append(view);
2593 for (const auto& frameView : frameViews)
2594 frameView->updateLayoutAndStyleIfNeededRecursive();
2596 // When an <iframe> gets composited, it triggers an extra style recalc in its containing FrameView.
2597 // To avoid pushing an invalid tree for display, we have to check for this case and do another
2598 // style recalc. The extra style recalc needs to happen after our child <iframes> were updated.
2599 // FIXME: We shouldn't be triggering an extra style recalc in the first place.
2600 if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) {
2601 m_frame->document()->updateRenderTreeIfNeeded();
2607 // These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
2608 ASSERT(!needsLayout());
2609 ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate());
2611 m_frame->document()->renderView()->assertRendererLaidOut();
2616 void FrameView::invalidateTreeIfNeededRecursive()
2618 // FIXME: We should be more aggressive at cutting tree traversals.
2619 lifecycle().advanceTo(DocumentLifecycle::InPaintInvalidation);
2620 invalidateTreeIfNeeded();
2621 lifecycle().advanceTo(DocumentLifecycle::PaintInvalidationClean);
2623 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2624 if (!child->isLocalFrame())
2627 toLocalFrame(child)->view()->invalidateTreeIfNeededRecursive();
2630 m_doFullPaintInvalidation = false;
2633 void FrameView::enableAutoSizeMode(const IntSize& minSize, const IntSize& maxSize)
2635 if (!m_autoSizeInfo)
2636 m_autoSizeInfo = FrameViewAutoSizeInfo::create(this);
2638 m_autoSizeInfo->configureAutoSizeMode(minSize, maxSize);
2639 setLayoutSizeFixedToFrameSize(true);
2644 void FrameView::disposeAutoSizeInfo()
2646 if (!m_autoSizeInfo)
2649 setLayoutSizeFixedToFrameSize(false);
2653 // Since autosize mode forces the scrollbar mode, change them to being auto.
2654 setVerticalScrollbarLock(false);
2655 setHorizontalScrollbarLock(false);
2656 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
2657 m_autoSizeInfo.clear();
2660 void FrameView::forceLayout(bool allowSubtree)
2662 layout(allowSubtree);
2665 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2667 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2668 // the state of things before and after the layout
2669 if (RenderView* renderView = this->renderView()) {
2670 float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2671 float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2673 LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2674 LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2675 renderView->setLogicalWidth(flooredPageLogicalWidth);
2676 renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2677 renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2680 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2681 // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2682 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
2683 // implementation should not do this!
2684 bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode();
2685 const LayoutRect& documentRect = renderView->documentRect();
2686 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2687 if (docLogicalWidth > pageLogicalWidth) {
2688 FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor));
2689 FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize);
2690 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2691 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2693 flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2694 flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2695 renderView->setLogicalWidth(flooredPageLogicalWidth);
2696 renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2697 renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2700 const LayoutRect& updatedDocumentRect = renderView->documentRect();
2701 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2702 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2703 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2704 LayoutUnit clippedLogicalLeft = 0;
2705 if (!renderView->style()->isLeftToRightDirection())
2706 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2707 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2709 if (!horizontalWritingMode)
2710 overflow = overflow.transposedRect();
2711 renderView->clearLayoutOverflow();
2712 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2719 IntRect FrameView::convertFromRenderer(const RenderObject& renderer, const IntRect& rendererRect) const
2721 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer.localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
2723 // Convert from page ("absolute") to FrameView coordinates.
2724 rect.moveBy(-scrollPosition());
2729 IntRect FrameView::convertToRenderer(const RenderObject& renderer, const IntRect& viewRect) const
2731 IntRect rect = viewRect;
2733 // Convert from FrameView coords into page ("absolute") coordinates.
2734 rect.moveBy(scrollPosition());
2736 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2737 // move the rect for now.
2738 rect.setLocation(roundedIntPoint(renderer.absoluteToLocal(rect.location(), UseTransforms)));
2742 IntPoint FrameView::convertFromRenderer(const RenderObject& renderer, const IntPoint& rendererPoint) const
2744 IntPoint point = roundedIntPoint(renderer.localToAbsolute(rendererPoint, UseTransforms));
2746 // Convert from page ("absolute") to FrameView coordinates.
2747 point.moveBy(-scrollPosition());
2751 IntPoint FrameView::convertToRenderer(const RenderObject& renderer, const IntPoint& viewPoint) const
2753 IntPoint point = viewPoint;
2755 // Convert from FrameView coords into page ("absolute") coordinates.
2756 point += IntSize(scrollX(), scrollY());
2758 return roundedIntPoint(renderer.absoluteToLocal(point, UseTransforms));
2761 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2763 if (const FrameView* parentView = toFrameView(parent())) {
2764 // Get our renderer in the parent view
2765 RenderPart* renderer = m_frame->ownerRenderer();
2769 IntRect rect(localRect);
2770 // Add borders and padding??
2771 rect.move(renderer->borderLeft() + renderer->paddingLeft(),
2772 renderer->borderTop() + renderer->paddingTop());
2773 return parentView->convertFromRenderer(*renderer, rect);
2779 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
2781 if (const FrameView* parentView = toFrameView(parent())) {
2782 // Get our renderer in the parent view
2783 RenderPart* renderer = m_frame->ownerRenderer();
2787 IntRect rect = parentView->convertToRenderer(*renderer, parentRect);
2788 // Subtract borders and padding
2789 rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
2790 -renderer->borderTop() - renderer->paddingTop());
2797 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
2799 if (const FrameView* parentView = toFrameView(parent())) {
2800 // Get our renderer in the parent view
2801 RenderPart* renderer = m_frame->ownerRenderer();
2805 IntPoint point(localPoint);
2807 // Add borders and padding
2808 point.move(renderer->borderLeft() + renderer->paddingLeft(),
2809 renderer->borderTop() + renderer->paddingTop());
2810 return parentView->convertFromRenderer(*renderer, point);
2816 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
2818 if (const FrameView* parentView = toFrameView(parent())) {
2819 // Get our renderer in the parent view
2820 RenderPart* renderer = m_frame->ownerRenderer();
2824 IntPoint point = parentView->convertToRenderer(*renderer, parentPoint);
2825 // Subtract borders and padding
2826 point.move(-renderer->borderLeft() - renderer->paddingLeft(),
2827 -renderer->borderTop() - renderer->paddingTop());
2834 void FrameView::setTracksPaintInvalidations(bool trackPaintInvalidations)
2836 if (trackPaintInvalidations == m_isTrackingPaintInvalidations)
2839 for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
2840 if (!frame->isLocalFrame())
2842 if (RenderView* renderView = toLocalFrame(frame)->contentRenderer())
2843 renderView->compositor()->setTracksPaintInvalidations(trackPaintInvalidations);
2846 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
2847 "FrameView::setTracksPaintInvalidations", "enabled", trackPaintInvalidations);
2849 resetTrackedPaintInvalidations();
2850 m_isTrackingPaintInvalidations = trackPaintInvalidations;
2853 void FrameView::resetTrackedPaintInvalidations()
2855 m_trackedPaintInvalidationRects.clear();
2856 if (RenderView* renderView = this->renderView())
2857 renderView->compositor()->resetTrackedPaintInvalidationRects();
2860 String FrameView::trackedPaintInvalidationRectsAsText() const
2863 if (!m_trackedPaintInvalidationRects.isEmpty()) {
2864 ts << "(repaint rects\n";
2865 for (size_t i = 0; i < m_trackedPaintInvalidationRects.size(); ++i)
2866 ts << " (rect " << m_trackedPaintInvalidationRects[i].x() << " " << m_trackedPaintInvalidationRects[i].y() << " " << m_trackedPaintInvalidationRects[i].width() << " " << m_trackedPaintInvalidationRects[i].height() << ")\n";
2869 return ts.release();
2872 void FrameView::addResizerArea(RenderBox& resizerBox)
2874 if (!m_resizerAreas)
2875 m_resizerAreas = adoptPtr(new ResizerAreaSet);
2876 m_resizerAreas->add(&resizerBox);
2879 void FrameView::removeResizerArea(RenderBox& resizerBox)
2881 if (!m_resizerAreas)
2884 ResizerAreaSet::iterator it = m_resizerAreas->find(&resizerBox);
2885 if (it != m_resizerAreas->end())
2886 m_resizerAreas->remove(it);
2889 void FrameView::addScrollableArea(ScrollableArea* scrollableArea)
2891 ASSERT(scrollableArea);
2892 if (!m_scrollableAreas)
2893 m_scrollableAreas = adoptPtr(new ScrollableAreaSet);
2894 m_scrollableAreas->add(scrollableArea);
2897 void FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
2899 if (!m_scrollableAreas)
2901 m_scrollableAreas->remove(scrollableArea);
2904 void FrameView::setParent(Widget* parentView)
2906 if (parentView == parent())
2909 if (m_scrollbarsAvoidingResizer && parent())
2910 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
2912 Widget::setParent(parentView);
2914 if (m_scrollbarsAvoidingResizer && parent())
2915 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
2917 updateScrollableAreaSet();
2920 void FrameView::removeChild(Widget* child)
2922 ASSERT(child->parent() == this);
2924 if (child->isFrameView())
2925 removeScrollableArea(toFrameView(child));
2927 child->setParent(0);
2928 m_children.remove(child);
2931 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
2933 bool allowScrolling = userInputScrollable(HorizontalScrollbar) || userInputScrollable(VerticalScrollbar);
2935 // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
2936 // should handle wheel events.
2937 #if !USE(RUBBER_BANDING)
2938 if (!isScrollable())
2939 allowScrolling = false;
2942 if (m_frame->settings()->rootLayerScrolls())
2943 allowScrolling = false;
2945 if (allowScrolling && ScrollableArea::handleWheelEvent(wheelEvent))
2948 // If the frame didn't handle the event, give the pinch-zoom viewport a chance to
2949 // process the scroll event.
2950 if (m_frame->settings()->pinchVirtualViewportEnabled() && m_frame->isMainFrame())
2951 return page()->frameHost().pinchViewport().handleWheelEvent(wheelEvent);
2956 bool FrameView::isVerticalDocument() const
2958 RenderView* renderView = this->renderView();
2962 return renderView->style()->isHorizontalWritingMode();
2965 bool FrameView::isFlippedDocument() const
2967 RenderView* renderView = this->renderView();
2971 return renderView->hasFlippedBlocksWritingMode();
2974 bool FrameView::scrollbarsDisabled() const
2976 if (!m_frame->settings() || !m_frame->settings()->pinchVirtualViewportEnabled())
2979 // FIXME: This decision should be made based on whether or not to use
2980 // viewport scrollbars for the main frame. This is implicitly just Android,
2981 // but should be made explicit.
2982 // http://crbug.com/434533
2986 return m_frame->isMainFrame();
2990 AXObjectCache* FrameView::axObjectCache() const
2992 if (frame().document())
2993 return frame().document()->existingAXObjectCache();
2997 void FrameView::setCursor(const Cursor& cursor)
2999 Page* page = frame().page();
3000 if (!page || !page->settings().deviceSupportsMouse())
3002 page->chrome().setCursor(cursor);
3005 void FrameView::frameRectsChanged()
3007 if (layoutSizeFixedToFrameSize())
3008 setLayoutSizeInternal(frameRect().size());
3010 for (const auto& child : m_children)
3011 child->frameRectsChanged();
3014 void FrameView::setLayoutSizeInternal(const IntSize& size)
3016 if (m_layoutSize == size)
3019 m_layoutSize = size;
3023 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3025 ScrollableArea::didAddScrollbar(scrollbar, orientation);
3026 if (AXObjectCache* cache = axObjectCache())
3027 cache->handleScrollbarUpdate(this);
3030 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3032 ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
3033 if (AXObjectCache* cache = axObjectCache()) {
3034 cache->remove(scrollbar);
3035 cache->handleScrollbarUpdate(this);
3039 void FrameView::setTopControlsViewportAdjustment(float adjustment)
3041 m_topControlsViewportAdjustment = adjustment;
3044 IntPoint FrameView::maximumScrollPosition() const
3046 // Make the same calculation as in CC's LayerImpl::MaxScrollOffset()
3047 // FIXME: We probably shouldn't be storing the bounds in a float. crbug.com/422331.
3048 FloatSize visibleSize = unscaledVisibleContentSize(ExcludeScrollbars);
3049 visibleSize.expand(0, m_topControlsViewportAdjustment);
3051 FloatSize contentBounds = contentsSize();
3052 contentBounds.scale(visibleContentScaleFactor());
3053 contentBounds = flooredIntSize(contentBounds);
3055 FloatSize maximumOffset = contentBounds - visibleSize - toIntSize(scrollOrigin());
3057 // Convert back to CSS pixels.
3058 maximumOffset.scale(1 / visibleContentScaleFactor());
3060 IntPoint snappedMaximumOffset = flooredIntPoint(maximumOffset);
3061 snappedMaximumOffset.clampNegativeToZero();
3062 return snappedMaximumOffset;
3065 void FrameView::addChild(PassRefPtrWillBeRawPtr<Widget> prpChild)
3067 Widget* child = prpChild.get();
3068 ASSERT(child != this && !child->parent());
3069 child->setParent(this);
3070 m_children.add(prpChild);
3073 void FrameView::setHasHorizontalScrollbar(bool hasBar)
3075 if (hasBar && !m_horizontalScrollbar) {
3076 m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
3077 addChild(m_horizontalScrollbar.get());
3078 didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
3079 m_horizontalScrollbar->styleChanged();
3080 } else if (!hasBar && m_horizontalScrollbar) {
3081 willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
3082 // If the scrollbar has been marked as overlapping the window resizer,
3083 // then its removal should reduce the count.
3084 if (m_horizontalScrollbar->overlapsResizer())
3085 adjustScrollbarsAvoidingResizerCount(-1);
3086 removeChild(m_horizontalScrollbar.get());
3087 m_horizontalScrollbar = nullptr;
3091 void FrameView::setHasVerticalScrollbar(bool hasBar)
3093 if (hasBar && !m_verticalScrollbar) {
3094 m_verticalScrollbar = createScrollbar(VerticalScrollbar);
3095 addChild(m_verticalScrollbar.get());
3096 didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
3097 m_verticalScrollbar->styleChanged();
3098 } else if (!hasBar && m_verticalScrollbar) {
3099 willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
3100 // If the scrollbar has been marked as overlapping the window resizer,
3101 // then its removal should reduce the count.
3102 if (m_verticalScrollbar->overlapsResizer())
3103 adjustScrollbarsAvoidingResizerCount(-1);
3104 removeChild(m_verticalScrollbar.get());
3105 m_verticalScrollbar = nullptr;
3109 void FrameView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
3110 bool horizontalLock, bool verticalLock)
3112 bool needsUpdate = false;
3114 if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
3115 m_horizontalScrollbarMode = horizontalMode;
3119 if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
3120 m_verticalScrollbarMode = verticalMode;
3125 setHorizontalScrollbarLock();
3128 setVerticalScrollbarLock();
3133 updateScrollbars(scrollOffsetDouble());
3135 if (!layerForScrolling())
3137 blink::WebLayer* layer = layerForScrolling()->platformLayer();
3140 layer->setUserScrollable(userInputScrollable(HorizontalScrollbar), userInputScrollable(VerticalScrollbar));
3143 void FrameView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
3145 horizontalMode = m_horizontalScrollbarMode;
3146 verticalMode = m_verticalScrollbarMode;
3149 void FrameView::setClipsRepaints(bool clipsRepaints)
3151 m_clipsRepaints = clipsRepaints;
3154 IntSize FrameView::unscaledVisibleContentSize(IncludeScrollbarsInRect scrollbarInclusion) const
3156 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(frameRect().size()) : frameRect().size();
3159 IntSize FrameView::excludeScrollbars(const IntSize& size) const
3161 int verticalScrollbarWidth = 0;
3162 int horizontalScrollbarHeight = 0;
3164 if (Scrollbar* verticalBar = verticalScrollbar())
3165 verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0;
3166 if (Scrollbar* horizontalBar = horizontalScrollbar())
3167 horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0;
3169 return IntSize(std::max(0, size.width() - verticalScrollbarWidth),
3170 std::max(0, size.height() - horizontalScrollbarHeight));
3174 IntRect FrameView::visibleContentRect(IncludeScrollbarsInRect scollbarInclusion) const
3176 FloatSize visibleContentSize = unscaledVisibleContentSize(scollbarInclusion);
3177 visibleContentSize.scale(1 / visibleContentScaleFactor());
3178 return IntRect(flooredIntPoint(m_scrollPosition), expandedIntSize(visibleContentSize));
3181 IntSize FrameView::contentsSize() const
3183 return m_contentsSize;
3186 IntPoint FrameView::minimumScrollPosition() const
3188 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
3191 IntPoint FrameView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
3193 if (!constrainsScrollingToContentEdge())
3196 IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
3197 newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
3198 return newScrollPosition;
3201 DoublePoint FrameView::adjustScrollPositionWithinRange(const DoublePoint& scrollPoint) const
3203 if (!constrainsScrollingToContentEdge())
3205 DoublePoint newScrollPosition = scrollPoint.shrunkTo(
3206 maximumScrollPosition().x(), maximumScrollPosition().y());
3207 newScrollPosition = newScrollPosition.expandedTo(
3208 minimumScrollPosition().x(), minimumScrollPosition().y());
3209 return newScrollPosition;
3212 void FrameView::adjustScrollbarOpacity()
3214 if (m_horizontalScrollbar && layerForHorizontalScrollbar()) {
3215 bool isOpaqueScrollbar = !m_horizontalScrollbar->isOverlayScrollbar();
3216 layerForHorizontalScrollbar()->setContentsOpaque(isOpaqueScrollbar);
3218 if (m_verticalScrollbar && layerForVerticalScrollbar()) {
3219 bool isOpaqueScrollbar = !m_verticalScrollbar->isOverlayScrollbar();
3220 layerForVerticalScrollbar()->setContentsOpaque(isOpaqueScrollbar);
3224 int FrameView::scrollSize(ScrollbarOrientation orientation) const
3226 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
3228 // If no scrollbars are present, the content may still be scrollable.
3230 IntSize scrollSize = m_contentsSize - visibleContentRect().size();
3231 scrollSize.clampNegativeToZero();
3232 return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
3235 return scrollbar->totalSize() - scrollbar->visibleSize();
3238 void FrameView::setScrollOffset(const IntPoint& offset)
3240 scrollTo(DoublePoint(adjustScrollPositionWithinRange(offset)));
3243 void FrameView::setScrollOffset(const DoublePoint& offset)
3245 scrollTo(adjustScrollPositionWithinRange(offset));
3248 bool FrameView::scroll(ScrollDirection direction, ScrollGranularity granularity)
3250 ScrollDirection physicalDirection =
3251 toPhysicalDirection(direction, isVerticalDocument(), isFlippedDocument());
3253 return ScrollableArea::scroll(physicalDirection, granularity);
3256 IntSize FrameView::overhangAmount() const
3260 IntPoint currentScrollPosition = scrollPosition();
3261 IntPoint minScrollPosition = minimumScrollPosition();
3262 IntPoint maxScrollPosition = maximumScrollPosition();
3264 if (currentScrollPosition.x() < minScrollPosition.x())
3265 stretch.setWidth(currentScrollPosition.x() - minScrollPosition.x());
3266 if (currentScrollPosition.x() > maxScrollPosition.x())
3267 stretch.setWidth(currentScrollPosition.x() - maxScrollPosition.x());
3269 if (currentScrollPosition.y() < minScrollPosition.y())
3270 stretch.setHeight(currentScrollPosition.y() - minScrollPosition.y());
3271 if (currentScrollPosition.y() > maxScrollPosition.y())
3272 stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y());
3277 void FrameView::windowResizerRectChanged()
3279 updateScrollbars(scrollOffsetDouble());
3282 static bool useOverlayScrollbars()
3284 // FIXME: Need to detect the presence of CSS custom scrollbars, which are non-overlay regardless the ScrollbarTheme.
3285 return ScrollbarTheme::theme()->usesOverlayScrollbars();
3288 void FrameView::computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool& newHasVerticalScrollbar, const IntSize& docSize, ComputeScrollbarExistenceOption option) const
3290 bool hasHorizontalScrollbar = m_horizontalScrollbar;
3291 bool hasVerticalScrollbar = m_verticalScrollbar;
3293 newHasHorizontalScrollbar = hasHorizontalScrollbar;
3294 newHasVerticalScrollbar = hasVerticalScrollbar;
3296 if (m_frame->settings() && m_frame->settings()->rootLayerScrolls())
3299 ScrollbarMode hScroll = m_horizontalScrollbarMode;
3300 ScrollbarMode vScroll = m_verticalScrollbarMode;
3302 if (hScroll != ScrollbarAuto)
3303 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
3304 if (vScroll != ScrollbarAuto)
3305 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
3307 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto))
3310 if (hScroll == ScrollbarAuto)
3311 newHasHorizontalScrollbar = docSize.width() > visibleWidth();
3312 if (vScroll == ScrollbarAuto)
3313 newHasVerticalScrollbar = docSize.height() > visibleHeight();
3315 if (useOverlayScrollbars())
3318 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size();
3320 bool attemptToRemoveScrollbars = (option == FirstPass
3321 && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height());
3322 if (attemptToRemoveScrollbars) {
3323 if (hScroll == ScrollbarAuto)
3324 newHasHorizontalScrollbar = false;
3325 if (vScroll == ScrollbarAuto)
3326 newHasVerticalScrollbar = false;
3329 // If we ever turn one scrollbar off, always turn the other one off too.
3330 // Never ever try to both gain/lose a scrollbar in the same pass.
3331 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
3332 newHasVerticalScrollbar = false;
3333 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
3334 newHasHorizontalScrollbar = false;
3337 void FrameView::updateScrollbarGeometry()
3339 if (m_horizontalScrollbar) {
3340 int clientWidth = visibleWidth();
3341 IntRect oldRect(m_horizontalScrollbar->frameRect());
3342 IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScrollbar) ? m_verticalScrollbar->width() : 0,
3343 height() - m_horizontalScrollbar->height(),
3344 width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
3345 m_horizontalScrollbar->height());
3346 m_horizontalScrollbar->setFrameRect(adjustScrollbarRectForResizer(hBarRect, m_horizontalScrollbar.get()));
3347 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
3348 m_horizontalScrollbar->invalidate();
3350 if (m_scrollbarsSuppressed)
3351 m_horizontalScrollbar->setSuppressInvalidation(true);
3352 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
3353 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
3354 m_horizontalScrollbar->offsetDidChange();
3355 if (m_scrollbarsSuppressed)
3356 m_horizontalScrollbar->setSuppressInvalidation(false);
3359 if (m_verticalScrollbar) {
3360 int clientHeight = visibleHeight();
3361 IntRect oldRect(m_verticalScrollbar->frameRect());
3362 IntRect vBarRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
3364 m_verticalScrollbar->width(),
3365 height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
3366 m_verticalScrollbar->setFrameRect(adjustScrollbarRectForResizer(vBarRect, m_verticalScrollbar.get()));
3367 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
3368 m_verticalScrollbar->invalidate();
3370 if (m_scrollbarsSuppressed)
3371 m_verticalScrollbar->setSuppressInvalidation(true);
3372 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
3373 m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
3374 m_verticalScrollbar->offsetDidChange();
3375 if (m_scrollbarsSuppressed)
3376 m_verticalScrollbar->setSuppressInvalidation(false);
3380 IntRect FrameView::adjustScrollbarRectForResizer(const IntRect& rect, Scrollbar* scrollbar)
3382 // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
3384 IntRect adjustedRect(rect);
3385 bool overlapsResizer = false;
3386 if (!rect.isEmpty() && !windowResizerRect().isEmpty()) {
3387 IntRect resizerRect = convertFromContainingWindow(windowResizerRect());
3388 if (rect.intersects(resizerRect)) {
3389 if (scrollbar->orientation() == HorizontalScrollbar) {
3390 int overlap = rect.maxX() - resizerRect.x();
3391 if (overlap > 0 && resizerRect.maxX() >= rect.maxX()) {
3392 adjustedRect.setWidth(rect.width() - overlap);
3393 overlapsResizer = true;
3396 int overlap = rect.maxY() - resizerRect.y();
3397 if (overlap > 0 && resizerRect.maxY() >= rect.maxY()) {
3398 adjustedRect.setHeight(rect.height() - overlap);
3399 overlapsResizer = true;
3404 if (overlapsResizer != scrollbar->overlapsResizer()) {
3405 scrollbar->setOverlapsResizer(overlapsResizer);
3406 adjustScrollbarsAvoidingResizerCount(overlapsResizer ? 1 : -1);
3408 return adjustedRect;
3411 bool FrameView::adjustScrollbarExistence(ComputeScrollbarExistenceOption option)
3413 ASSERT(m_inUpdateScrollbars);
3415 // If we came in here with the view already needing a layout, then go ahead and do that
3416 // first. (This will be the common case, e.g., when the page changes due to window resizing for example).
3417 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
3418 if (!m_scrollbarsSuppressed)
3419 scrollbarExistenceDidChange();
3421 bool hasHorizontalScrollbar = m_horizontalScrollbar;
3422 bool hasVerticalScrollbar = m_verticalScrollbar;
3424 bool newHasHorizontalScrollbar = false;
3425 bool newHasVerticalScrollbar = false;
3426 computeScrollbarExistence(newHasHorizontalScrollbar, newHasVerticalScrollbar, contentsSize(), option);
3428 bool scrollbarExistenceChanged = hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar;
3429 if (!scrollbarExistenceChanged)
3432 setHasHorizontalScrollbar(newHasHorizontalScrollbar);
3433 setHasVerticalScrollbar(newHasVerticalScrollbar);
3435 if (m_scrollbarsSuppressed)
3438 if (!useOverlayScrollbars())
3440 scrollbarExistenceDidChange();
3444 void FrameView::updateScrollbars(const DoubleSize& desiredOffset)
3446 if (scrollbarsDisabled()) {
3447 setScrollOffsetFromUpdateScrollbars(desiredOffset);
3451 if (m_inUpdateScrollbars)
3453 InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
3455 IntSize oldVisibleSize = visibleSize();
3457 bool scrollbarExistenceChanged = false;
3458 int maxUpdateScrollbarsPass = useOverlayScrollbars() || m_scrollbarsSuppressed ? 1 : 3;
3459 for (int updateScrollbarsPass = 0; updateScrollbarsPass < maxUpdateScrollbarsPass; updateScrollbarsPass++) {
3460 if (!adjustScrollbarExistence(updateScrollbarsPass ? Incremental : FirstPass))
3462 scrollbarExistenceChanged = true;
3465 updateScrollbarGeometry();
3467 if (scrollbarExistenceChanged) {
3468 // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
3469 frameRectsChanged();
3470 positionScrollbarLayers();
3471 updateScrollCorner();
3474 // FIXME: We don't need to do this if we are composited.
3475 IntSize newVisibleSize = visibleSize();
3476 if (newVisibleSize.width() > oldVisibleSize.width()) {
3477 if (shouldPlaceVerticalScrollbarOnLeft())
3478 invalidateRect(IntRect(0, 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height()));
3480 invalidateRect(IntRect(oldVisibleSize.width(), 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height()));
3482 if (newVisibleSize.height() > oldVisibleSize.height())
3483 invalidateRect(IntRect(0, oldVisibleSize.height(), newVisibleSize.width(), newVisibleSize.height() - oldVisibleSize.height()));
3485 setScrollOffsetFromUpdateScrollbars(desiredOffset);
3488 void FrameView::setScrollOffsetFromUpdateScrollbars(const DoubleSize& offset)
3490 DoublePoint adjustedScrollPosition = DoublePoint(offset);
3492 if (!isRubberBandInProgress())
3493 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition);
3495 if (adjustedScrollPosition != scrollPositionDouble() || scrollOriginChanged()) {
3496 ScrollableArea::scrollToOffsetWithoutAnimation(toFloatPoint(adjustedScrollPosition));
3497 resetScrollOriginChanged();
3501 const int panIconSizeLength = 16;
3503 IntRect FrameView::rectToCopyOnScroll() const
3505 IntRect scrollViewRect = convertToContainingWindow(IntRect((shouldPlaceVerticalScrollbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visibleWidth(), visibleHeight()));
3506 if (hasOverlayScrollbars()) {
3507 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
3508 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
3510 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
3511 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
3513 return scrollViewRect;
3516 void FrameView::scrollContentsIfNeeded()
3518 if (m_pendingScrollDelta.isZero())
3520 DoubleSize scrollDelta = m_pendingScrollDelta;
3521 m_pendingScrollDelta = DoubleSize();
3522 // FIXME: Change scrollContents() to take DoubleSize. crbug.com/414283.
3523 scrollContents(flooredIntSize(scrollDelta));
3526 void FrameView::scrollContents(const IntSize& scrollDelta)
3528 HostWindow* window = hostWindow();
3532 IntRect clipRect = windowClipRect();
3533 IntRect updateRect = clipRect;
3534 updateRect.intersect(rectToCopyOnScroll());
3536 if (m_shouldDrawPanScrollIcon) {
3537 // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
3538 // https://bugs.webkit.org/show_bug.cgi?id=47837
3539 int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + std::max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
3540 IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
3541 IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
3542 panScrollIconDirtyRect.intersect(clipRect);
3543 window->invalidateContentsAndRootView(panScrollIconDirtyRect);
3546 if (!scrollContentsFastPath(-scrollDelta))
3547 scrollContentsSlowPath(updateRect);
3549 // Invalidate the overhang areas if they are visible.
3550 updateOverhangAreas();
3552 // This call will move children with native widgets (plugins) and invalidate them as well.
3553 frameRectsChanged();
3556 IntPoint FrameView::rootViewToContents(const IntPoint& rootViewPoint) const
3558 IntPoint viewPoint = convertFromContainingWindow(rootViewPoint);
3559 return viewPoint + scrollOffset();
3562 IntPoint FrameView::contentsToRootView(const IntPoint& contentsPoint) const
3564 IntPoint viewPoint = contentsPoint - scrollOffset();
3565 return convertToContainingWindow(viewPoint);
3568 IntRect FrameView::rootViewToContents(const IntRect& rootViewRect) const
3570 IntRect viewRect = convertFromContainingWindow(rootViewRect);
3571 viewRect.move(scrollOffset());
3575 IntRect FrameView::contentsToRootView(const IntRect& contentsRect) const
3577 IntRect viewRect = contentsRect;
3578 viewRect.move(-scrollOffset());
3579 return convertToContainingWindow(viewRect);
3582 IntPoint FrameView::windowToContents(const IntPoint& windowPoint) const
3584 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
3585 return viewPoint + scrollOffset();
3588 FloatPoint FrameView::windowToContents(const FloatPoint& windowPoint) const
3590 FloatPoint viewPoint = convertFromContainingWindow(windowPoint);
3591 return viewPoint + scrollOffset();
3594 IntPoint FrameView::contentsToWindow(const IntPoint& contentsPoint) const
3596 IntPoint viewPoint = contentsPoint - scrollOffset();
3597 return convertToContainingWindow(viewPoint);
3600 IntRect FrameView::windowToContents(const IntRect& windowRect) const
3602 IntRect viewRect = convertFromContainingWindow(windowRect);
3603 viewRect.move(scrollOffset());
3607 IntRect FrameView::contentsToWindow(const IntRect& contentsRect) const
3609 IntRect viewRect = contentsRect;
3610 viewRect.move(-scrollOffset());
3611 return convertToContainingWindow(viewRect);
3614 IntRect FrameView::contentsToScreen(const IntRect& rect) const
3616 HostWindow* window = hostWindow();
3619 return window->rootViewToScreen(contentsToRootView(rect));
3622 bool FrameView::containsScrollbarsAvoidingResizer() const
3624 return !m_scrollbarsAvoidingResizer;
3627 void FrameView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
3629 int oldCount = m_scrollbarsAvoidingResizer;
3630 m_scrollbarsAvoidingResizer += overlapDelta;
3632 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(overlapDelta);
3633 } else if (!scrollbarsSuppressed()) {
3634 // If we went from n to 0 or from 0 to n and we're the outermost view,
3635 // we need to invalidate the windowResizerRect(), since it will now need to paint
3637 if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0)
3638 || (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
3639 invalidateRect(windowResizerRect());
3643 void FrameView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
3645 if (suppressed == m_scrollbarsSuppressed)
3648 m_scrollbarsSuppressed = suppressed;
3650 if (repaintOnUnsuppress && !suppressed) {
3651 if (m_horizontalScrollbar)
3652 m_horizontalScrollbar->invalidate();
3653 if (m_verticalScrollbar)
3654 m_verticalScrollbar->invalidate();
3656 // Invalidate the scroll corner too on unsuppress.
3657 invalidateRect(scrollCornerRect());
3661 Scrollbar* FrameView::scrollbarAtWindowPoint(const IntPoint& windowPoint)
3663 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
3664 return scrollbarAtViewPoint(viewPoint);
3667 Scrollbar* FrameView::scrollbarAtViewPoint(const IntPoint& viewPoint)
3669 if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint))
3670 return m_horizontalScrollbar.get();
3671 if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint))
3672 return m_verticalScrollbar.get();
3676 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
3678 if (!graphicsLayer || !scrollbar)
3681 IntRect scrollbarRect = scrollbar->frameRect();
3682 graphicsLayer->setPosition(scrollbarRect.location());
3684 if (scrollbarRect.size() == graphicsLayer->size())
3687 graphicsLayer->setSize(scrollbarRect.size());
3689 if (graphicsLayer->hasContentsLayer()) {
3690 graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
3694 graphicsLayer->setDrawsContent(true);
3695 graphicsLayer->setNeedsDisplay();
3698 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
3702 graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
3703 graphicsLayer->setPosition(cornerRect.location());
3704 if (cornerRect.size() != graphicsLayer->size())
3705 graphicsLayer->setNeedsDisplay();
3706 graphicsLayer->setSize(cornerRect.size());
3709 void FrameView::positionScrollbarLayers()
3711 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
3712 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
3713 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
3716 bool FrameView::userInputScrollable(ScrollbarOrientation orientation) const
3718 Document* document = frame().document();
3719 Element* fullscreenElement = Fullscreen::fullscreenElementFrom(*document);
3720 if (fullscreenElement && fullscreenElement != document->documentElement())
3723 ScrollbarMode mode = (orientation == HorizontalScrollbar) ?
3724 m_horizontalScrollbarMode : m_verticalScrollbarMode;
3726 return mode == ScrollbarAuto || mode == ScrollbarAlwaysOn;
3729 bool FrameView::shouldPlaceVerticalScrollbarOnLeft() const
3734 IntRect FrameView::scrollCornerRect() const
3738 if (hasOverlayScrollbars())
3741 if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
3742 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : m_horizontalScrollbar->width(),
3743 height() - m_horizontalScrollbar->height(),
3744 width() - m_horizontalScrollbar->width(),
3745 m_horizontalScrollbar->height()));
3748 if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
3749 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
3750 m_verticalScrollbar->height(),
3751 m_verticalScrollbar->width(),
3752 height() - m_verticalScrollbar->height()));
3758 bool FrameView::isScrollCornerVisible() const
3760 return !scrollCornerRect().isEmpty();
3763 void FrameView::invalidateScrollCornerRect(const IntRect& rect)
3765 invalidateRect(rect);
3768 void FrameView::paintPanScrollIcon(GraphicsContext* context)
3770 DEFINE_STATIC_REF(Image, panScrollIcon, (Image::loadPlatformResource("panIcon")));
3771 IntPoint iconGCPoint = m_panScrollIconPoint;
3773 iconGCPoint = toFrameView(parent())->windowToContents(iconGCPoint);
3774 context->drawImage(panScrollIcon, iconGCPoint);
3777 void FrameView::paint(GraphicsContext* context, const IntRect& rect)
3779 FramePainter(*this).paint(context, rect);
3782 void FrameView::paintContents(GraphicsContext* context, const IntRect& damageRect)
3784 FramePainter(*this).paintContents(context, damageRect);
3787 void FrameView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
3789 int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
3790 ? verticalScrollbar()->width() : 0;
3791 int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
3792 ? horizontalScrollbar()->height() : 0;
3794 int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
3795 if (physicalScrollY < 0) {
3796 horizontalOverhangRect = frameRect();
3797 horizontalOverhangRect.setHeight(-physicalScrollY);
3798 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
3799 } else if (physicalScrollY > 0 && contentsHeight() && physicalScrollY > contentsHeight() - visibleHeight()) {
3800 int height = physicalScrollY - (contentsHeight() - visibleHeight());
3801 horizontalOverhangRect = frameRect();
3802 horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
3803 horizontalOverhangRect.setHeight(height);
3804 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth);
3807 int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
3808 if (physicalScrollX < 0) {
3809 verticalOverhangRect.setWidth(-physicalScrollX);
3810 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
3811 verticalOverhangRect.setX(frameRect().x());
3812 if (horizontalOverhangRect.y() == frameRect().y())
3813 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
3815 verticalOverhangRect.setY(frameRect().y());
3816 } else if (physicalScrollX > 0 && contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) {
3817 int width = physicalScrollX - (contentsWidth() - visibleWidth());
3818 verticalOverhangRect.setWidth(width);
3819 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight);
3820 verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
3821 if (horizontalOverhangRect.y() == frameRect().y())
3822 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
3824 verticalOverhangRect.setY(frameRect().y());
3828 void FrameView::updateOverhangAreas()
3830 HostWindow* window = hostWindow();
3834 IntRect horizontalOverhangRect;
3835 IntRect verticalOverhangRect;
3836 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
3837 if (!horizontalOverhangRect.isEmpty())
3838 window->invalidateContentsAndRootView(horizontalOverhangRect);
3839 if (!verticalOverhangRect.isEmpty())
3840 window->invalidateContentsAndRootView(verticalOverhangRect);
3843 bool FrameView::isPointInScrollbarCorner(const IntPoint& windowPoint)
3845 if (!scrollbarCornerPresent())
3848 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
3850 if (m_horizontalScrollbar) {
3851 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
3852 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
3853 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
3855 return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
3858 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
3859 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
3860 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
3862 return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
3865 bool FrameView::scrollbarCornerPresent() const
3867 return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
3868 || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
3871 IntRect FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
3873 // Scrollbars won't be transformed within us
3874 IntRect newRect = localRect;
3875 newRect.moveBy(scrollbar->location());
3879 IntRect FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
3881 IntRect newRect = parentRect;
3882 // Scrollbars won't be transformed within us
3883 newRect.moveBy(-scrollbar->location());
3887 // FIXME: test these on windows
3888 IntPoint FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
3890 // Scrollbars won't be transformed within us
3891 IntPoint newPoint = localPoint;
3892 newPoint.moveBy(scrollbar->location());
3896 IntPoint FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
3898 IntPoint newPoint = parentPoint;
3899 // Scrollbars won't be transformed within us
3900 newPoint.moveBy(-scrollbar->location());
3904 void FrameView::setParentVisible(bool visible)
3906 if (isParentVisible() == visible)
3909 Widget::setParentVisible(visible);
3911 if (!isSelfVisible())
3914 for (const auto& child : m_children)
3915 child->setParentVisible(visible);
3918 void FrameView::show()
3920 if (!isSelfVisible()) {
3921 setSelfVisible(true);
3922 if (isParentVisible()) {
3923 for (const auto& child : m_children)
3924 child->setParentVisible(true);
3931 void FrameView::hide()
3933 if (isSelfVisible()) {
3934 if (isParentVisible()) {
3935 for (const auto& child : m_children)
3936 child->setParentVisible(false);
3938 setSelfVisible(false);
3944 void FrameView::addPanScrollIcon(const IntPoint& iconPosition)
3946 HostWindow* window = hostWindow();
3949 m_shouldDrawPanScrollIcon = true;
3950 m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2);
3951 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
3954 void FrameView::removePanScrollIcon()
3956 HostWindow* window = hostWindow();
3959 m_shouldDrawPanScrollIcon = false;
3960 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)));
3963 void FrameView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
3965 if (scrollOrigin() == origin)
3968 ScrollableArea::setScrollOrigin(origin);
3970 // Update if the scroll origin changes, since our position will be different if the content size did not change.
3971 if (updatePositionAtAll && updatePositionSynchronously)
3972 updateScrollbars(scrollOffsetDouble());
3975 } // namespace blink