Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / frame / FrameView.cpp
bloba956cd4ee393e62f18998302b8d94965cdf65e8a
1 /*
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.
27 #include "config.h"
28 #include "core/frame/FrameView.h"
30 #include "core/HTMLNames.h"
31 #include "core/MediaTypeNames.h"
32 #include "core/compositing/DisplayListCompositingBuilder.h"
33 #include "core/css/FontFaceSet.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/AXObjectCache.h"
36 #include "core/dom/Fullscreen.h"
37 #include "core/editing/EditingUtilities.h"
38 #include "core/editing/FrameSelection.h"
39 #include "core/editing/RenderedPosition.h"
40 #include "core/editing/markers/DocumentMarkerController.h"
41 #include "core/fetch/ResourceFetcher.h"
42 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
43 #include "core/frame/FrameHost.h"
44 #include "core/frame/LocalFrame.h"
45 #include "core/frame/Settings.h"
46 #include "core/html/HTMLFrameElement.h"
47 #include "core/html/HTMLPlugInElement.h"
48 #include "core/html/HTMLTextFormControlElement.h"
49 #include "core/html/parser/TextResourceDecoder.h"
50 #include "core/input/EventHandler.h"
51 #include "core/inspector/InspectorInstrumentation.h"
52 #include "core/inspector/InspectorTraceEvents.h"
53 #include "core/layout/LayoutAnalyzer.h"
54 #include "core/layout/LayoutCounter.h"
55 #include "core/layout/LayoutEmbeddedObject.h"
56 #include "core/layout/LayoutInline.h"
57 #include "core/layout/LayoutListBox.h"
58 #include "core/layout/LayoutPart.h"
59 #include "core/layout/LayoutScrollbar.h"
60 #include "core/layout/LayoutScrollbarPart.h"
61 #include "core/layout/LayoutTableCell.h"
62 #include "core/layout/LayoutTheme.h"
63 #include "core/layout/LayoutView.h"
64 #include "core/layout/ScrollAlignment.h"
65 #include "core/layout/TextAutosizer.h"
66 #include "core/layout/TracedLayoutObject.h"
67 #include "core/layout/compositing/CompositedDeprecatedPaintLayerMapping.h"
68 #include "core/layout/compositing/CompositedSelection.h"
69 #include "core/layout/compositing/DeprecatedPaintLayerCompositor.h"
70 #include "core/layout/svg/LayoutSVGRoot.h"
71 #include "core/loader/FrameLoader.h"
72 #include "core/loader/FrameLoaderClient.h"
73 #include "core/page/AutoscrollController.h"
74 #include "core/page/ChromeClient.h"
75 #include "core/page/FocusController.h"
76 #include "core/page/FrameTree.h"
77 #include "core/page/Page.h"
78 #include "core/page/scrolling/ScrollingCoordinator.h"
79 #include "core/paint/DeprecatedPaintLayer.h"
80 #include "core/paint/FramePainter.h"
81 #include "core/style/ComputedStyle.h"
82 #include "core/svg/SVGDocumentExtensions.h"
83 #include "core/svg/SVGSVGElement.h"
84 #include "platform/HostWindow.h"
85 #include "platform/RuntimeEnabledFeatures.h"
86 #include "platform/ScriptForbiddenScope.h"
87 #include "platform/TraceEvent.h"
88 #include "platform/TracedValue.h"
89 #include "platform/fonts/FontCache.h"
90 #include "platform/geometry/DoubleRect.h"
91 #include "platform/geometry/FloatRect.h"
92 #include "platform/geometry/LayoutRect.h"
93 #include "platform/graphics/GraphicsContext.h"
94 #include "platform/graphics/GraphicsLayer.h"
95 #include "platform/graphics/GraphicsLayerDebugInfo.h"
96 #include "platform/graphics/paint/DisplayItemList.h"
97 #include "platform/scroll/ScrollAnimator.h"
98 #include "platform/text/TextStream.h"
99 #include "wtf/CurrentTime.h"
100 #include "wtf/StdLibExtras.h"
101 #include "wtf/TemporaryChange.h"
103 namespace blink {
105 using namespace HTMLNames;
107 // The maximum number of updateWidgets iterations that should be done before returning.
108 static const unsigned maxUpdateWidgetsIterations = 2;
109 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
111 static bool s_initialTrackAllPaintInvalidations = false;
113 FrameView::FrameView(LocalFrame* frame)
114 : m_frame(frame)
115 , m_displayMode(WebDisplayModeBrowser)
116 , m_canHaveScrollbars(true)
117 , m_slowRepaintObjectCount(0)
118 , m_hasPendingLayout(false)
119 , m_inSynchronousPostLayout(false)
120 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
121 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
122 , m_isTransparent(false)
123 , m_baseBackgroundColor(Color::white)
124 , m_mediaType(MediaTypeNames::screen)
125 , m_safeToPropagateScrollToParent(true)
126 , m_isTrackingPaintInvalidations(false)
127 , m_scrollCorner(nullptr)
128 , m_inputEventsScaleFactorForEmulation(1)
129 , m_layoutSizeFixedToFrameSize(true)
130 , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
131 , m_topControlsViewportAdjustment(0)
132 , m_needsUpdateWidgetPositions(false)
133 #if ENABLE(ASSERT)
134 , m_hasBeenDisposed(false)
135 #endif
136 , m_horizontalScrollbarMode(ScrollbarAuto)
137 , m_verticalScrollbarMode(ScrollbarAuto)
138 , m_horizontalScrollbarLock(false)
139 , m_verticalScrollbarLock(false)
140 , m_scrollbarsAvoidingResizer(0)
141 , m_scrollbarsSuppressed(false)
142 , m_inUpdateScrollbars(false)
143 , m_clipsRepaints(true)
144 , m_frameTimingRequestsDirty(true)
147 ASSERT(m_frame);
148 init();
151 PassRefPtrWillBeRawPtr<FrameView> FrameView::create(LocalFrame* frame)
153 RefPtrWillBeRawPtr<FrameView> view = adoptRefWillBeNoop(new FrameView(frame));
154 view->show();
155 return view.release();
158 PassRefPtrWillBeRawPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
160 RefPtrWillBeRawPtr<FrameView> view = adoptRefWillBeNoop(new FrameView(frame));
161 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
162 view->setLayoutSizeInternal(initialSize);
164 view->show();
165 return view.release();
168 FrameView::~FrameView()
170 ASSERT(m_hasBeenDisposed);
171 #if !ENABLE(OILPAN)
172 // Verify that the LocalFrame has a different FrameView or
173 // that it is being detached and destructed.
174 ASSERT(frame().view() != this || !layoutView());
175 #endif
178 DEFINE_TRACE(FrameView)
180 #if ENABLE(OILPAN)
181 visitor->trace(m_frame);
182 visitor->trace(m_nodeToDraw);
183 visitor->trace(m_scrollAnchor);
184 visitor->trace(m_scrollableAreas);
185 visitor->trace(m_animatingScrollableAreas);
186 visitor->trace(m_autoSizeInfo);
187 visitor->trace(m_horizontalScrollbar);
188 visitor->trace(m_verticalScrollbar);
189 visitor->trace(m_children);
190 visitor->trace(m_viewportScrollableArea);
191 #endif
192 Widget::trace(visitor);
193 ScrollableArea::trace(visitor);
196 void FrameView::reset()
198 m_hasPendingLayout = false;
199 m_doFullPaintInvalidation = false;
200 m_layoutSchedulingEnabled = true;
201 m_inPerformLayout = false;
202 m_inSynchronousPostLayout = false;
203 m_layoutCount = 0;
204 m_nestedLayoutCount = 0;
205 m_postLayoutTasksTimer.stop();
206 m_updateWidgetsTimer.stop();
207 m_firstLayout = true;
208 m_safeToPropagateScrollToParent = true;
209 m_lastViewportSize = IntSize();
210 m_lastZoomFactor = 1.0f;
211 m_isTrackingPaintInvalidations = s_initialTrackAllPaintInvalidations;
212 m_lastPaintTime = 0;
213 m_isPainting = false;
214 m_visuallyNonEmptyCharacterCount = 0;
215 m_visuallyNonEmptyPixelCount = 0;
216 m_isVisuallyNonEmpty = false;
217 clearScrollAnchor();
218 m_viewportConstrainedObjects.clear();
219 m_layoutSubtreeRootList.clear();
222 void FrameView::removeFromAXObjectCache()
224 if (AXObjectCache* cache = axObjectCache()) {
225 cache->remove(this);
226 cache->childrenChanged(m_frame->pagePopupOwner());
230 void FrameView::init()
232 reset();
234 m_size = LayoutSize();
236 // Propagate the marginwidth/height and scrolling modes to the view.
237 // FIXME: Do we need to do this for OOPI?
238 Element* ownerElement = m_frame->deprecatedLocalOwner();
239 if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) {
240 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
241 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
242 setCanHaveScrollbars(false);
246 void FrameView::dispose()
248 RELEASE_ASSERT(!isInPerformLayout());
250 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
251 scrollAnimator->cancelAnimations();
252 cancelProgrammaticScrollAnimation();
254 detachScrollbars();
256 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
257 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
258 removeFromAXObjectCache();
260 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
261 scrollingCoordinator->willDestroyScrollableArea(this);
263 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing
264 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|.
265 m_autoSizeInfo.clear();
267 if (m_postLayoutTasksTimer.isActive())
268 m_postLayoutTasksTimer.stop();
270 if (m_didScrollTimer.isActive())
271 m_didScrollTimer.stop();
273 // FIXME: Do we need to do something here for OOPI?
274 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
275 // TODO(dcheng): It seems buggy that we can have an owner element that
276 // points to another Widget.
277 if (ownerElement && ownerElement->ownedWidget() == this)
278 ownerElement->setWidget(nullptr);
280 #if ENABLE(ASSERT)
281 m_hasBeenDisposed = true;
282 #endif
285 void FrameView::detachScrollbars()
287 // Previously, we detached custom scrollbars as early as possible to prevent
288 // Document::detach() from messing with the view such that its scroll bars
289 // won't be torn down. However, scripting in Document::detach() is forbidden
290 // now, so it's not clear if these edge cases can still happen.
291 // However, for Oilpan, we still need to remove the native scrollbars before
292 // we lose the connection to the HostWindow, so we just unconditionally
293 // detach any scrollbars now.
294 setHasHorizontalScrollbar(false);
295 setHasVerticalScrollbar(false);
297 if (m_scrollCorner) {
298 m_scrollCorner->destroy();
299 m_scrollCorner = nullptr;
303 void FrameView::recalculateCustomScrollbarStyle()
305 bool didStyleChange = false;
306 if (m_horizontalScrollbar && m_horizontalScrollbar->isCustomScrollbar()) {
307 m_horizontalScrollbar->styleChanged();
308 didStyleChange = true;
310 if (m_verticalScrollbar && m_verticalScrollbar->isCustomScrollbar()) {
311 m_verticalScrollbar->styleChanged();
312 didStyleChange = true;
314 if (didStyleChange) {
315 updateScrollbarGeometry();
316 updateScrollCorner();
317 positionScrollbarLayers();
321 void FrameView::invalidateAllCustomScrollbarsOnActiveChanged()
323 bool usesWindowInactiveSelector = m_frame->document()->styleEngine().usesWindowInactiveSelector();
325 const ChildrenWidgetSet* viewChildren = children();
326 for (const RefPtrWillBeMember<Widget>& child : *viewChildren) {
327 Widget* widget = child.get();
328 if (widget->isFrameView())
329 toFrameView(widget)->invalidateAllCustomScrollbarsOnActiveChanged();
330 else if (usesWindowInactiveSelector && widget->isScrollbar() && toScrollbar(widget)->isCustomScrollbar())
331 toScrollbar(widget)->styleChanged();
333 if (usesWindowInactiveSelector)
334 recalculateCustomScrollbarStyle();
337 void FrameView::recalculateScrollbarOverlayStyle()
339 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
340 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
342 Color backgroundColor = documentBackgroundColor();
343 // Reduce the background color from RGB to a lightness value
344 // and determine which scrollbar style to use based on a lightness
345 // heuristic.
346 double hue, saturation, lightness;
347 backgroundColor.getHSL(hue, saturation, lightness);
348 if (lightness <= .5)
349 overlayStyle = ScrollbarOverlayStyleLight;
351 if (oldOverlayStyle != overlayStyle)
352 setScrollbarOverlayStyle(overlayStyle);
355 void FrameView::clear()
357 reset();
358 setScrollbarsSuppressed(true);
361 bool FrameView::didFirstLayout() const
363 return !m_firstLayout;
366 void FrameView::invalidateRect(const IntRect& rect)
368 // For querying DeprecatedPaintLayer::compositingState() when invalidating scrollbars.
369 // FIXME: do all scrollbar invalidations after layout of all frames is complete. It's currently not recursively true.
370 DisableCompositingQueryAsserts disabler;
371 if (!parent()) {
372 if (HostWindow* window = hostWindow())
373 window->invalidateRect(rect);
374 return;
377 LayoutPart* layoutObject = m_frame->ownerLayoutObject();
378 if (!layoutObject)
379 return;
381 IntRect paintInvalidationRect = rect;
382 paintInvalidationRect.move(layoutObject->borderLeft() + layoutObject->paddingLeft(),
383 layoutObject->borderTop() + layoutObject->paddingTop());
384 // FIXME: We should not allow paint invalidation out of paint invalidation state. crbug.com/457415
385 DisablePaintInvalidationStateAsserts paintInvalidationAssertDisabler;
386 layoutObject->invalidatePaintRectangle(LayoutRect(paintInvalidationRect));
389 void FrameView::setFrameRect(const IntRect& newRect)
391 IntRect oldRect = frameRect();
392 if (newRect == oldRect)
393 return;
395 Widget::setFrameRect(newRect);
397 updateScrollbars(scrollOffsetDouble());
398 frameRectsChanged();
400 updateScrollableAreaSet();
402 if (LayoutView* layoutView = this->layoutView()) {
403 if (layoutView->usesCompositing())
404 layoutView->compositor()->frameViewDidChangeSize();
407 viewportSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
409 if (oldRect.size() != newRect.size()) {
410 if (m_frame->isMainFrame())
411 m_frame->host()->visualViewport().mainFrameDidChangeSize();
412 frame().loader().restoreScrollPositionAndViewState();
416 Page* FrameView::page() const
418 return frame().page();
421 LayoutView* FrameView::layoutView() const
423 return frame().contentLayoutObject();
426 ScrollingCoordinator* FrameView::scrollingCoordinator()
428 Page* p = page();
429 return p ? p->scrollingCoordinator() : 0;
432 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
434 m_canHaveScrollbars = canHaveScrollbars;
436 ScrollbarMode newVerticalMode = m_verticalScrollbarMode;
437 if (canHaveScrollbars && m_verticalScrollbarMode == ScrollbarAlwaysOff)
438 newVerticalMode = ScrollbarAuto;
439 else if (!canHaveScrollbars)
440 newVerticalMode = ScrollbarAlwaysOff;
442 ScrollbarMode newHorizontalMode = m_horizontalScrollbarMode;
443 if (canHaveScrollbars && m_horizontalScrollbarMode == ScrollbarAlwaysOff)
444 newHorizontalMode = ScrollbarAuto;
445 else if (!canHaveScrollbars)
446 newHorizontalMode = ScrollbarAlwaysOff;
448 setScrollbarModes(newHorizontalMode, newVerticalMode);
451 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame) const
453 customScrollbarElement = nullptr;
454 customScrollbarFrame = nullptr;
456 if (Settings* settings = m_frame->settings()) {
457 if (!settings->allowCustomScrollbarInMainFrame() && m_frame->isMainFrame())
458 return false;
461 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
462 Document* doc = m_frame->document();
464 // Try the <body> element first as a scrollbar source.
465 Element* body = doc ? doc->body() : 0;
466 if (body && body->layoutObject() && body->layoutObject()->style()->hasPseudoStyle(SCROLLBAR)) {
467 customScrollbarElement = body;
468 return true;
471 // If the <body> didn't have a custom style, then the root element might.
472 Element* docElement = doc ? doc->documentElement() : 0;
473 if (docElement && docElement->layoutObject() && docElement->layoutObject()->style()->hasPseudoStyle(SCROLLBAR)) {
474 customScrollbarElement = docElement;
475 return true;
478 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
479 LayoutPart* frameLayoutObject = m_frame->ownerLayoutObject();
480 if (frameLayoutObject && frameLayoutObject->style()->hasPseudoStyle(SCROLLBAR)) {
481 customScrollbarFrame = m_frame.get();
482 return true;
485 return false;
488 PassRefPtrWillBeRawPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
490 Element* customScrollbarElement = nullptr;
491 LocalFrame* customScrollbarFrame = nullptr;
492 if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
493 return LayoutScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
495 // Nobody set a custom style, so we just use a native scrollbar.
496 return Scrollbar::create(this, orientation, RegularScrollbar);
499 void FrameView::setContentsSize(const IntSize& size)
501 if (size == contentsSize())
502 return;
504 m_contentsSize = size;
505 updateScrollbars(scrollOffsetDouble());
506 ScrollableArea::contentsResized();
508 Page* page = frame().page();
509 if (!page)
510 return;
512 updateScrollableAreaSet();
514 page->chromeClient().contentsSizeChanged(m_frame.get(), size);
515 frame().loader().restoreScrollPositionAndViewState();
518 void FrameView::adjustViewSize()
520 LayoutView* layoutView = this->layoutView();
521 if (!layoutView)
522 return;
524 ASSERT(m_frame->view() == this);
526 const IntRect rect = layoutView->documentRect();
527 const IntSize& size = rect.size();
528 setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
530 setContentsSize(size);
533 void FrameView::applyOverflowToViewport(LayoutObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
535 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
536 // overflow:hidden and overflow:scroll on <body> as applying to the document's
537 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
538 // use the root element.
540 EOverflow overflowX = o->style()->overflowX();
541 EOverflow overflowY = o->style()->overflowY();
543 if (o->isSVGRoot()) {
544 // Don't allow overflow to affect <img> and css backgrounds
545 if (toLayoutSVGRoot(o)->isEmbeddedThroughSVGImage())
546 return;
548 // FIXME: evaluate if we can allow overflow for these cases too.
549 // Overflow is always hidden when stand-alone SVG documents are embedded.
550 if (toLayoutSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
551 overflowX = OHIDDEN;
552 overflowY = OHIDDEN;
556 switch (overflowX) {
557 case OHIDDEN:
558 if (!shouldIgnoreOverflowHidden())
559 hMode = ScrollbarAlwaysOff;
560 break;
561 case OSCROLL:
562 hMode = ScrollbarAlwaysOn;
563 break;
564 case OAUTO:
565 hMode = ScrollbarAuto;
566 break;
567 default:
568 // Don't set it at all.
572 switch (overflowY) {
573 case OHIDDEN:
574 if (!shouldIgnoreOverflowHidden())
575 vMode = ScrollbarAlwaysOff;
576 break;
577 case OSCROLL:
578 vMode = ScrollbarAlwaysOn;
579 break;
580 case OAUTO:
581 vMode = ScrollbarAuto;
582 break;
583 default:
584 // Don't set it at all.
589 void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
591 // FIXME: How do we handle this for OOPI?
592 const HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
593 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
594 hMode = ScrollbarAlwaysOff;
595 vMode = ScrollbarAlwaysOff;
596 return;
599 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
600 hMode = ScrollbarAuto;
601 vMode = ScrollbarAuto;
602 } else {
603 hMode = ScrollbarAlwaysOff;
604 vMode = ScrollbarAlwaysOff;
607 if (!isSubtreeLayout()) {
608 Document* document = m_frame->document();
609 Node* body = document->body();
610 if (isHTMLFrameSetElement(body) && body->layoutObject()) {
611 vMode = ScrollbarAlwaysOff;
612 hMode = ScrollbarAlwaysOff;
613 } else if (LayoutObject* viewport = viewportLayoutObject()) {
614 if (viewport->style())
615 applyOverflowToViewport(viewport, hMode, vMode);
620 void FrameView::updateAcceleratedCompositingSettings()
622 if (LayoutView* layoutView = this->layoutView())
623 layoutView->compositor()->updateAcceleratedCompositingSettings();
626 void FrameView::recalcOverflowAfterStyleChange()
628 LayoutView* layoutView = this->layoutView();
629 RELEASE_ASSERT(layoutView);
630 if (!layoutView->needsOverflowRecalcAfterStyleChange())
631 return;
633 layoutView->recalcOverflowAfterStyleChange();
635 // Changing overflow should notify scrolling coordinator to ensures that it
636 // updates non-fast scroll rects even if there is no layout.
637 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
638 scrollingCoordinator->notifyOverflowUpdated();
640 IntRect documentRect = layoutView->documentRect();
641 if (scrollOrigin() == -documentRect.location() && contentsSize() == documentRect.size())
642 return;
644 if (needsLayout())
645 return;
647 InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
649 bool shouldHaveHorizontalScrollbar = false;
650 bool shouldHaveVerticalScrollbar = false;
651 computeScrollbarExistence(shouldHaveHorizontalScrollbar, shouldHaveVerticalScrollbar, documentRect.size());
653 bool hasHorizontalScrollbar = horizontalScrollbar();
654 bool hasVerticalScrollbar = verticalScrollbar();
655 if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar
656 || hasVerticalScrollbar != shouldHaveVerticalScrollbar) {
657 setNeedsLayout();
658 return;
661 adjustViewSize();
662 updateScrollbarGeometry();
665 bool FrameView::usesCompositedScrolling() const
667 LayoutView* layoutView = this->layoutView();
668 if (!layoutView)
669 return false;
670 if (m_frame->settings() && m_frame->settings()->preferCompositingToLCDTextEnabled())
671 return layoutView->compositor()->inCompositingMode();
672 return false;
675 GraphicsLayer* FrameView::layerForScrolling() const
677 LayoutView* layoutView = this->layoutView();
678 if (!layoutView)
679 return nullptr;
680 return layoutView->compositor()->frameScrollLayer();
683 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
685 LayoutView* layoutView = this->layoutView();
686 if (!layoutView)
687 return nullptr;
688 return layoutView->compositor()->layerForHorizontalScrollbar();
691 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
693 LayoutView* layoutView = this->layoutView();
694 if (!layoutView)
695 return nullptr;
696 return layoutView->compositor()->layerForVerticalScrollbar();
699 GraphicsLayer* FrameView::layerForScrollCorner() const
701 LayoutView* layoutView = this->layoutView();
702 if (!layoutView)
703 return nullptr;
704 return layoutView->compositor()->layerForScrollCorner();
707 bool FrameView::isEnclosedInCompositingLayer() const
709 // FIXME: It's a bug that compositing state isn't always up to date when this is called. crbug.com/366314
710 DisableCompositingQueryAsserts disabler;
712 LayoutObject* frameOwnerLayoutObject = m_frame->ownerLayoutObject();
713 return frameOwnerLayoutObject && frameOwnerLayoutObject->enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
716 void FrameView::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isSubtree)
718 needsLayoutObjects = 0;
719 totalObjects = 0;
720 isSubtree = isSubtreeLayout();
721 if (isSubtree)
722 m_layoutSubtreeRootList.countObjectsNeedingLayout(needsLayoutObjects, totalObjects);
723 else
724 LayoutSubtreeRootList::countObjectsNeedingLayoutInRoot(layoutView(), needsLayoutObjects, totalObjects);
727 inline void FrameView::forceLayoutParentViewIfNeeded()
729 LayoutPart* ownerLayoutObject = m_frame->ownerLayoutObject();
730 if (!ownerLayoutObject || !ownerLayoutObject->frame())
731 return;
733 LayoutBox* contentBox = embeddedContentBox();
734 if (!contentBox)
735 return;
737 LayoutSVGRoot* svgRoot = toLayoutSVGRoot(contentBox);
738 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
739 return;
741 // If the embedded SVG document appears the first time, the ownerLayoutObject has already finished
742 // layout without knowing about the existence of the embedded SVG document, because LayoutReplaced
743 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
744 // bothering to lay out the SVG document, mark the ownerLayoutObject needing layout and ask its
745 // FrameView for a layout. After that the LayoutEmbeddedObject (ownerLayoutObject) carries the
746 // correct size, which LayoutSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
747 // out for the first time, or when the LayoutSVGRoot size has changed dynamically (eg. via <script>).
748 RefPtrWillBeRawPtr<FrameView> frameView = ownerLayoutObject->frame()->view();
750 // Mark the owner layoutObject as needing layout.
751 ownerLayoutObject->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::Unknown);
753 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
754 ASSERT(frameView);
755 frameView->layout();
758 void FrameView::performPreLayoutTasks()
760 TRACE_EVENT0("blink,benchmark", "FrameView::performPreLayoutTasks");
761 lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
763 // Don't schedule more layouts, we're in one.
764 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
766 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
767 // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
768 m_inSynchronousPostLayout = true;
769 performPostLayoutTasks();
770 m_inSynchronousPostLayout = false;
773 bool wasResized = wasViewportResized();
774 Document* document = m_frame->document();
776 // Viewport-dependent media queries may cause us to need completely different style information.
777 if (!document->styleResolver() || (wasResized && document->styleResolver()->mediaQueryAffectedByViewportChange())) {
778 document->mediaQueryAffectingValueChanged();
779 } else if (wasResized) {
780 document->evaluateMediaQueryList();
783 document->updateLayoutTreeIfNeeded();
784 lifecycle().advanceTo(DocumentLifecycle::StyleClean);
786 if (m_frame->isMainFrame() && !m_viewportScrollableArea) {
787 ScrollableArea& visualViewport = m_frame->host()->visualViewport();
788 ScrollableArea* layoutViewport = layoutViewportScrollableArea();
789 bool invertScrollOrder = m_frame->settings()->invertViewportScrollOrder();
790 ASSERT(layoutViewport);
791 m_viewportScrollableArea = RootFrameViewport::create(visualViewport, *layoutViewport, invertScrollOrder);
795 static inline void layoutFromRootObject(LayoutObject& root)
797 LayoutState layoutState(root);
798 root.layout();
801 void FrameView::prepareLayoutAnalyzer()
803 bool isTracing = false;
804 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
805 if (!isTracing) {
806 m_analyzer.clear();
807 return;
809 if (!m_analyzer)
810 m_analyzer = adoptPtr(new LayoutAnalyzer());
811 m_analyzer->reset();
814 PassRefPtr<TracedValue> FrameView::analyzerCounters()
816 if (!m_analyzer)
817 return TracedValue::create();
818 RefPtr<TracedValue> value = m_analyzer->toTracedValue();
819 value->setString("host", layoutView()->document().location()->host());
820 return value;
823 #define PERFORM_LAYOUT_TRACE_CATEGORIES "blink,benchmark," TRACE_DISABLED_BY_DEFAULT("blink.debug.layout")
825 void FrameView::performLayout(bool inSubtreeLayout)
827 ASSERT(inSubtreeLayout || m_layoutSubtreeRootList.isEmpty());
829 TRACE_EVENT_BEGIN0(PERFORM_LAYOUT_TRACE_CATEGORIES, "FrameView::performLayout");
830 prepareLayoutAnalyzer();
832 ScriptForbiddenScope forbidScript;
834 ASSERT(!isInPerformLayout());
835 lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
837 TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
839 // performLayout is the actual guts of layout().
840 // FIXME: The 300 other lines in layout() probably belong in other helper functions
841 // so that a single human could understand what layout() is actually doing.
843 forceLayoutParentViewIfNeeded();
845 if (inSubtreeLayout) {
846 if (m_analyzer)
847 m_analyzer->increment(LayoutAnalyzer::PerformLayoutRootLayoutObjects, m_layoutSubtreeRootList.size());
848 while (LayoutObject* root = m_layoutSubtreeRootList.takeDeepestRoot()) {
849 if (!root->needsLayout())
850 continue;
851 layoutFromRootObject(*root);
853 // We need to ensure that we mark up all layoutObjects up to the LayoutView
854 // for paint invalidation. This simplifies our code as we just always
855 // do a full tree walk.
856 if (LayoutObject* container = root->container())
857 container->setMayNeedPaintInvalidation();
859 } else {
860 layoutFromRootObject(*layoutView());
863 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
865 lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
867 TRACE_EVENT_END1(PERFORM_LAYOUT_TRACE_CATEGORIES, "FrameView::performLayout",
868 "counters", analyzerCounters());
871 void FrameView::scheduleOrPerformPostLayoutTasks()
873 if (m_postLayoutTasksTimer.isActive())
874 return;
876 if (!m_inSynchronousPostLayout) {
877 m_inSynchronousPostLayout = true;
878 // Calls resumeScheduledEvents()
879 performPostLayoutTasks();
880 m_inSynchronousPostLayout = false;
883 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
884 // If we need layout or are already in a synchronous call to postLayoutTasks(),
885 // defer widget updates and event dispatch until after we return. postLayoutTasks()
886 // can make us need to update again, and we can get stuck in a nasty cycle unless
887 // we call it through the timer here.
888 m_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
889 if (needsLayout())
890 layout();
894 void FrameView::layout()
896 // We should never layout a Document which is not in a LocalFrame.
897 ASSERT(m_frame);
898 ASSERT(m_frame->view() == this);
899 ASSERT(m_frame->page());
901 ScriptForbiddenScope forbidScript;
903 if (isInPerformLayout() || !m_frame->document()->isActive())
904 return;
906 TRACE_EVENT0("blink,benchmark", "FrameView::layout");
907 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout");
909 // Protect the view from being deleted during layout (in recalcStyle)
910 RefPtrWillBeRawPtr<FrameView> protector(this);
912 if (m_autoSizeInfo)
913 m_autoSizeInfo->autoSizeIfNeeded();
915 m_hasPendingLayout = false;
916 DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
918 RELEASE_ASSERT(!isPainting());
920 TRACE_EVENT_BEGIN1("devtools.timeline", "Layout", "beginData", InspectorLayoutEvent::beginData(this));
922 performPreLayoutTasks();
924 #if !ENABLE(OILPAN)
925 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
926 // so there's no point to continuing to layout
927 if (protector->hasOneRef())
928 return;
929 #endif
931 Document* document = m_frame->document();
933 // If the layout view was marked as needing layout after we added items in the subtree roots we need
934 // to clear the roots and do the layout from the layoutView.
935 if (layoutView()->needsLayout())
936 clearLayoutSubtreeRootsAndMarkContainingBlocks();
937 layoutView()->clearHitTestCache();
939 bool inSubtreeLayout = isSubtreeLayout();
941 // FIXME: The notion of a single root for layout is no longer applicable. Remove or update this code. crbug.com/460596
942 LayoutObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRootList.randomRoot() : layoutView();
943 if (!rootForThisLayout) {
944 // FIXME: Do we need to set m_size here?
945 ASSERT_NOT_REACHED();
946 return;
949 FontCachePurgePreventer fontCachePurgePreventer;
951 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
953 m_nestedLayoutCount++;
954 if (!inSubtreeLayout) {
955 clearLayoutSubtreeRootsAndMarkContainingBlocks();
956 Node* body = document->body();
957 if (body && body->layoutObject()) {
958 if (isHTMLFrameSetElement(*body)) {
959 body->layoutObject()->setChildNeedsLayout();
960 } else if (isHTMLBodyElement(*body)) {
961 if (!m_firstLayout && m_size.height() != layoutSize().height() && body->layoutObject()->enclosingBox()->stretchesToViewport())
962 body->layoutObject()->setChildNeedsLayout();
966 updateCounters();
968 ScrollbarMode hMode;
969 ScrollbarMode vMode;
970 calculateScrollbarModesForLayout(hMode, vMode);
972 if (!inSubtreeLayout) {
973 // Now set our scrollbar state for the layout.
974 ScrollbarMode currentHMode = horizontalScrollbarMode();
975 ScrollbarMode currentVMode = verticalScrollbarMode();
977 if (m_firstLayout) {
978 setScrollbarsSuppressed(true);
980 m_doFullPaintInvalidation = true;
981 m_firstLayout = false;
982 m_lastViewportSize = layoutSize(IncludeScrollbars);
983 m_lastZoomFactor = layoutView()->style()->zoom();
985 // Set the initial vMode to AlwaysOn if we're auto.
986 if (vMode == ScrollbarAuto)
987 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
988 // Set the initial hMode to AlwaysOff if we're auto.
989 if (hMode == ScrollbarAuto)
990 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
992 setScrollbarModes(hMode, vMode);
993 setScrollbarsSuppressed(false, true);
994 } else if (hMode != currentHMode || vMode != currentVMode) {
995 setScrollbarModes(hMode, vMode);
998 if (needsScrollbarReconstruction())
999 updateScrollbars(scrollOffsetDouble());
1001 LayoutSize oldSize = m_size;
1003 m_size = LayoutSize(layoutSize().width(), layoutSize().height());
1005 if (oldSize != m_size && !m_firstLayout) {
1006 LayoutBox* rootLayoutObject = document->documentElement() ? document->documentElement()->layoutBox() : 0;
1007 LayoutBox* bodyLayoutObject = rootLayoutObject && document->body() ? document->body()->layoutBox() : 0;
1008 if (bodyLayoutObject && bodyLayoutObject->stretchesToViewport())
1009 bodyLayoutObject->setChildNeedsLayout();
1010 else if (rootLayoutObject && rootLayoutObject->stretchesToViewport())
1011 rootLayoutObject->setChildNeedsLayout();
1014 // We need to set m_doFullPaintInvalidation before triggering layout as LayoutObject::checkForPaintInvalidation
1015 // checks the boolean to disable local paint invalidations.
1016 m_doFullPaintInvalidation |= layoutView()->shouldDoFullPaintInvalidationForNextLayout();
1019 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), "LayoutTree",
1020 this, TracedLayoutObject::create(*layoutView(), false));
1022 performLayout(inSubtreeLayout);
1024 ASSERT(m_layoutSubtreeRootList.isEmpty());
1025 } // Reset m_layoutSchedulingEnabled to its previous value.
1027 if (!inSubtreeLayout && !document->printing())
1028 adjustViewSize();
1030 m_frameTimingRequestsDirty = true;
1032 // FIXME: Could find the common ancestor layer of all dirty subtrees and mark from there. crbug.com/462719
1033 layoutView()->enclosingLayer()->updateLayerPositionsAfterLayout();
1035 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), "LayoutTree",
1036 this, TracedLayoutObject::create(*layoutView(), true));
1038 layoutView()->compositor()->didLayout();
1040 m_layoutCount++;
1042 if (AXObjectCache* cache = document->axObjectCache()) {
1043 const KURL& url = document->url();
1044 if (url.isValid() && !url.isAboutBlankURL())
1045 cache->handleLayoutComplete(document);
1047 updateAnnotatedRegions();
1049 scheduleOrPerformPostLayoutTasks();
1051 // FIXME: The notion of a single root for layout is no longer applicable. Remove or update this code. crbug.com/460596
1052 TRACE_EVENT_END1("devtools.timeline", "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout));
1053 InspectorInstrumentation::didUpdateLayout(m_frame.get());
1055 m_nestedLayoutCount--;
1056 if (m_nestedLayoutCount)
1057 return;
1059 #if ENABLE(ASSERT)
1060 // Post-layout assert that nobody was re-marked as needing layout during layout.
1061 layoutView()->assertSubtreeIsLaidOut();
1062 #endif
1064 // Ensure that we become visually non-empty eventually.
1065 // TODO(esprehn): This should check isRenderingReady() instead.
1066 if (!frame().document()->parsing() && frame().loader().stateMachine()->committedFirstRealDocumentLoad())
1067 m_isVisuallyNonEmpty = true;
1069 // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
1070 // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
1071 // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from
1072 // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
1073 // necessitating this check here.
1074 // ASSERT(frame()->page());
1075 if (frame().page())
1076 frame().page()->chromeClient().layoutUpdated(m_frame.get());
1078 frame().document()->layoutUpdated();
1081 // The plan is to move to compositor-queried paint invalidation, in which case this
1082 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
1083 // let the compositor pick which to actually draw.
1084 // See http://crbug.com/306706
1085 void FrameView::invalidateTreeIfNeeded(PaintInvalidationState& paintInvalidationState)
1087 lifecycle().advanceTo(DocumentLifecycle::InPaintInvalidation);
1089 ASSERT(layoutView());
1090 LayoutView& rootForPaintInvalidation = *layoutView();
1091 ASSERT(!rootForPaintInvalidation.needsLayout());
1093 TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation.debugName().ascii());
1095 rootForPaintInvalidation.invalidateTreeIfNeeded(paintInvalidationState);
1097 // Invalidate the paint of the frameviews scrollbars if needed
1098 if (hasVerticalBarDamage())
1099 invalidateRect(verticalBarDamage());
1100 if (hasHorizontalBarDamage())
1101 invalidateRect(horizontalBarDamage());
1102 resetScrollbarDamage();
1104 #if ENABLE(ASSERT)
1105 layoutView()->assertSubtreeClearedPaintInvalidationState();
1106 #endif
1108 if (m_frame->selection().isCaretBoundsDirty())
1109 m_frame->selection().invalidateCaretRect();
1111 m_doFullPaintInvalidation = false;
1112 lifecycle().advanceTo(DocumentLifecycle::PaintInvalidationClean);
1115 DocumentLifecycle& FrameView::lifecycle() const
1117 return m_frame->document()->lifecycle();
1120 LayoutBox* FrameView::embeddedContentBox() const
1122 LayoutView* layoutView = this->layoutView();
1123 if (!layoutView)
1124 return nullptr;
1126 LayoutObject* firstChild = layoutView->firstChild();
1127 if (!firstChild || !firstChild->isBox())
1128 return nullptr;
1130 // Curently only embedded SVG documents participate in the size-negotiation logic.
1131 if (firstChild->isSVGRoot())
1132 return toLayoutBox(firstChild);
1134 return nullptr;
1138 void FrameView::addPart(LayoutPart* object)
1140 m_parts.add(object);
1143 void FrameView::removePart(LayoutPart* object)
1145 m_parts.remove(object);
1148 void FrameView::updateWidgetPositions()
1150 Vector<RefPtr<LayoutPart>> parts;
1151 copyToVector(m_parts, parts);
1153 // Script or plugins could detach the frame so abort processing if that happens.
1155 for (size_t i = 0; i < parts.size() && layoutView(); ++i)
1156 parts[i]->updateWidgetPosition();
1158 for (size_t i = 0; i < parts.size() && layoutView(); ++i)
1159 parts[i]->widgetPositionsUpdated();
1162 void FrameView::addPartToUpdate(LayoutEmbeddedObject& object)
1164 ASSERT(isInPerformLayout());
1165 // Tell the DOM element that it needs a widget update.
1166 Node* node = object.node();
1167 ASSERT(node);
1168 if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node))
1169 toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1171 m_partUpdateSet.add(&object);
1174 void FrameView::setDisplayMode(WebDisplayMode mode)
1176 if (mode == m_displayMode)
1177 return;
1179 m_displayMode = mode;
1181 if (m_frame->document())
1182 m_frame->document()->mediaQueryAffectingValueChanged();
1185 void FrameView::setMediaType(const AtomicString& mediaType)
1187 ASSERT(m_frame->document());
1188 m_frame->document()->mediaQueryAffectingValueChanged();
1189 m_mediaType = mediaType;
1192 AtomicString FrameView::mediaType() const
1194 // See if we have an override type.
1195 if (m_frame->settings() && !m_frame->settings()->mediaTypeOverride().isEmpty())
1196 return AtomicString(m_frame->settings()->mediaTypeOverride());
1197 return m_mediaType;
1200 void FrameView::adjustMediaTypeForPrinting(bool printing)
1202 if (printing) {
1203 if (m_mediaTypeWhenNotPrinting.isNull())
1204 m_mediaTypeWhenNotPrinting = mediaType();
1205 setMediaType(MediaTypeNames::print);
1206 } else {
1207 if (!m_mediaTypeWhenNotPrinting.isNull())
1208 setMediaType(m_mediaTypeWhenNotPrinting);
1209 m_mediaTypeWhenNotPrinting = nullAtom;
1213 bool FrameView::contentsInCompositedLayer() const
1215 LayoutView* layoutView = this->layoutView();
1216 return layoutView && layoutView->compositingState() == PaintsIntoOwnBacking;
1219 void FrameView::addSlowRepaintObject()
1221 if (!m_slowRepaintObjectCount++) {
1222 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
1223 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1227 void FrameView::removeSlowRepaintObject()
1229 ASSERT(m_slowRepaintObjectCount > 0);
1230 m_slowRepaintObjectCount--;
1231 if (!m_slowRepaintObjectCount) {
1232 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
1233 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1237 void FrameView::addViewportConstrainedObject(LayoutObject* object)
1239 if (!m_viewportConstrainedObjects)
1240 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1242 if (!m_viewportConstrainedObjects->contains(object)) {
1243 m_viewportConstrainedObjects->add(object);
1245 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
1246 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1250 void FrameView::removeViewportConstrainedObject(LayoutObject* object)
1252 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1253 m_viewportConstrainedObjects->remove(object);
1255 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
1256 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1260 void FrameView::viewportSizeChanged(bool widthChanged, bool heightChanged)
1262 if (!hasViewportConstrainedObjects())
1263 return;
1265 for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
1266 LayoutObject* layoutObject = viewportConstrainedObject;
1267 const ComputedStyle& style = layoutObject->styleRef();
1268 if (widthChanged) {
1269 if (style.width().isFixed() && (style.left().isAuto() || style.right().isAuto()))
1270 layoutObject->setNeedsPositionedMovementLayout();
1271 else
1272 layoutObject->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SizeChanged);
1274 if (heightChanged) {
1275 if (style.height().isFixed() && (style.top().isAuto() || style.bottom().isAuto()))
1276 layoutObject->setNeedsPositionedMovementLayout();
1277 else
1278 layoutObject->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SizeChanged);
1283 IntPoint FrameView::lastKnownMousePosition() const
1285 return m_frame->eventHandler().lastKnownMousePosition();
1288 bool FrameView::shouldSetCursor() const
1290 Page* page = frame().page();
1291 return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive() && page->settings().deviceSupportsMouse();
1294 void FrameView::scrollContentsIfNeededRecursive()
1296 scrollContentsIfNeeded();
1298 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1299 if (!child->isLocalFrame())
1300 continue;
1301 if (FrameView* view = toLocalFrame(child)->view())
1302 view->scrollContentsIfNeededRecursive();
1306 bool FrameView::invalidateViewportConstrainedObjects()
1308 for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
1309 LayoutObject* layoutObject = viewportConstrainedObject;
1310 ASSERT(layoutObject->style()->hasViewportConstrainedPosition());
1311 ASSERT(layoutObject->hasLayer());
1312 DeprecatedPaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer();
1314 if (layer->isPaintInvalidationContainer())
1315 continue;
1317 if (layer->subtreeIsInvisible())
1318 continue;
1320 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1321 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1322 if (layer->hasAncestorWithFilterOutsets())
1323 return false;
1325 TRACE_EVENT_INSTANT1(
1326 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
1327 "ScrollInvalidationTracking",
1328 TRACE_EVENT_SCOPE_THREAD,
1329 "data",
1330 InspectorScrollInvalidationTrackingEvent::data(*layoutObject));
1332 layoutObject->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
1334 return true;
1337 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
1339 if (!contentsInCompositedLayer() || hasSlowRepaintObjects())
1340 return false;
1342 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1343 InspectorInstrumentation::didUpdateLayout(m_frame.get());
1344 return true;
1347 if (!invalidateViewportConstrainedObjects())
1348 return false;
1350 InspectorInstrumentation::didUpdateLayout(m_frame.get());
1351 return true;
1354 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1356 TRACE_EVENT0("blink", "FrameView::scrollContentsSlowPath");
1357 // We need full invalidation during slow scrolling. For slimming paint, full invalidation
1358 // of the LayoutView is not enough. We also need to invalidate all of the objects.
1359 // FIXME: Find out what are enough to invalidate in slow path scrolling. crbug.com/451090#9.
1360 ASSERT(layoutView());
1361 if (contentsInCompositedLayer())
1362 layoutView()->layer()->compositedDeprecatedPaintLayerMapping()->setContentsNeedDisplay();
1363 else
1364 layoutView()->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
1367 if (contentsInCompositedLayer()) {
1368 IntRect updateRect = visibleContentRect();
1369 ASSERT(layoutView());
1370 // FIXME: We should not allow paint invalidation out of paint invalidation state. crbug.com/457415
1371 DisablePaintInvalidationStateAsserts disabler;
1372 layoutView()->invalidatePaintRectangle(LayoutRect(updateRect));
1374 if (LayoutPart* frameLayoutObject = m_frame->ownerLayoutObject()) {
1375 if (isEnclosedInCompositingLayer()) {
1376 LayoutRect rect(frameLayoutObject->borderLeft() + frameLayoutObject->paddingLeft(),
1377 frameLayoutObject->borderTop() + frameLayoutObject->paddingTop(),
1378 visibleWidth(), visibleHeight());
1379 // FIXME: We should not allow paint invalidation out of paint invalidation state. crbug.com/457415
1380 DisablePaintInvalidationStateAsserts disabler;
1381 frameLayoutObject->invalidatePaintRectangle(rect);
1382 return;
1386 hostWindow()->invalidateRect(updateRect);
1389 void FrameView::restoreScrollbar()
1391 setScrollbarsSuppressed(false);
1394 bool FrameView::processUrlFragment(const KURL& url, UrlFragmentBehavior behavior)
1396 // If our URL has no ref, then we have no place we need to jump to.
1397 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1398 // and possibly paint invalidation because :target pseudo class may have been
1399 // set (see bug 11321).
1400 // Similarly for svg, if we had a previous svgView() then we need to reset
1401 // the initial view if we don't have a fragment.
1402 if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget() && !m_frame->document()->isSVGDocument())
1403 return false;
1405 String fragmentIdentifier = url.fragmentIdentifier();
1406 if (processUrlFragmentHelper(fragmentIdentifier, behavior))
1407 return true;
1409 // Try again after decoding the ref, based on the document's encoding.
1410 if (m_frame->document()->encoding().isValid())
1411 return processUrlFragmentHelper(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()), behavior);
1413 return false;
1416 bool FrameView::processUrlFragmentHelper(const String& name, UrlFragmentBehavior behavior)
1418 ASSERT(m_frame->document());
1420 if (behavior == UrlFragmentScroll && !m_frame->document()->isRenderingReady()) {
1421 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1422 return false;
1425 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1427 Element* anchorNode = m_frame->document()->findAnchor(name);
1429 // Setting to null will clear the current target.
1430 m_frame->document()->setCSSTarget(anchorNode);
1432 if (m_frame->document()->isSVGDocument()) {
1433 if (SVGSVGElement* svg = SVGDocumentExtensions::rootElement(*m_frame->document())) {
1434 svg->setupInitialView(name, anchorNode);
1435 if (!anchorNode)
1436 return true;
1440 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1441 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1442 return false;
1444 if (behavior == UrlFragmentScroll)
1445 maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1447 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1448 // If anchorNode is not focusable, setFocusedElement() will still clear focus, which matches the behavior of other browsers.
1449 if (anchorNode)
1450 m_frame->document()->setFocusedElement(anchorNode);
1452 return true;
1455 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1457 ASSERT(anchorNode);
1458 m_scrollAnchor = anchorNode;
1460 // We need to update the layout tree before scrolling.
1461 m_frame->document()->updateLayoutTreeIfNeeded();
1463 // If layout is needed, we will scroll in performPostLayoutTasks. Otherwise, scroll immediately.
1464 LayoutView* layoutView = this->layoutView();
1465 if (layoutView && layoutView->needsLayout())
1466 layout();
1467 else
1468 scrollToAnchor();
1471 void FrameView::clearScrollAnchor()
1473 m_scrollAnchor = nullptr;
1476 void FrameView::setScrollPosition(const DoublePoint& scrollPoint, ScrollType scrollType, ScrollBehavior scrollBehavior)
1478 DoublePoint newScrollPosition = clampScrollPosition(scrollPoint);
1479 if (newScrollPosition == scrollPositionDouble())
1480 return;
1482 if (scrollBehavior == ScrollBehaviorAuto)
1483 scrollBehavior = scrollBehaviorStyle();
1485 ScrollableArea::setScrollPosition(newScrollPosition, scrollType, scrollBehavior);
1488 void FrameView::didUpdateElasticOverscroll()
1490 Page* page = frame().page();
1491 if (!page)
1492 return;
1493 FloatSize elasticOverscroll = page->chromeClient().elasticOverscroll();
1494 if (m_horizontalScrollbar) {
1495 float delta = elasticOverscroll.width() - m_horizontalScrollbar->elasticOverscroll();
1496 if (delta != 0) {
1497 m_horizontalScrollbar->setElasticOverscroll(elasticOverscroll.width());
1498 scrollAnimator()->notifyContentAreaScrolled(FloatSize(delta, 0));
1499 if (!m_scrollbarsSuppressed)
1500 m_horizontalScrollbar->invalidate();
1503 if (m_verticalScrollbar) {
1504 float delta = elasticOverscroll.height() - m_verticalScrollbar->elasticOverscroll();
1505 if (delta != 0) {
1506 m_verticalScrollbar->setElasticOverscroll(elasticOverscroll.height());
1507 scrollAnimator()->notifyContentAreaScrolled(FloatSize(0, delta));
1508 if (!m_scrollbarsSuppressed)
1509 m_verticalScrollbar->invalidate();
1514 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1516 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1519 void FrameView::setLayoutSize(const IntSize& size)
1521 ASSERT(!layoutSizeFixedToFrameSize());
1523 setLayoutSizeInternal(size);
1526 void FrameView::scrollPositionChanged()
1528 Document* document = m_frame->document();
1529 document->enqueueScrollEventForNode(document);
1531 m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1533 if (LayoutView* layoutView = document->layoutView()) {
1534 if (layoutView->usesCompositing())
1535 layoutView->compositor()->frameViewDidScroll();
1538 if (m_didScrollTimer.isActive())
1539 m_didScrollTimer.stop();
1540 m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE);
1542 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1543 cache->handleScrollPositionChanged(this);
1545 layoutView()->clearHitTestCache();
1546 frame().loader().saveScrollState();
1549 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1551 if (m_frame->document() && m_frame->document()->layoutView()) {
1552 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1556 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
1558 // Nothing to do after scrolling if there are no fixed position elements.
1559 if (!hasViewportConstrainedObjects())
1560 return;
1562 RefPtrWillBeRawPtr<FrameView> protect(this);
1564 // If there fixed position elements, scrolling may cause compositing layers to change.
1565 // Update widget and layer positions after scrolling, but only if we're not inside of
1566 // layout.
1567 if (!m_nestedLayoutCount) {
1568 updateWidgetPositions();
1569 if (LayoutView* layoutView = this->layoutView())
1570 layoutView->layer()->setNeedsCompositingInputsUpdate();
1574 bool FrameView::computeCompositedSelection(LocalFrame& frame, CompositedSelection& selection)
1576 const VisibleSelection& visibleSelection = frame.selection().selection();
1577 if (!visibleSelection.isCaretOrRange())
1578 return false;
1580 // Non-editable caret selections lack any kind of UI affordance, and
1581 // needn't be tracked by the client.
1582 if (visibleSelection.isCaret() && !visibleSelection.isContentEditable())
1583 return false;
1585 VisiblePosition visibleStart(visibleSelection.visibleStart());
1586 RenderedPosition renderedStart(visibleStart);
1587 renderedStart.positionInGraphicsLayerBacking(selection.start);
1588 if (!selection.start.layer)
1589 return false;
1591 if (visibleSelection.isCaret()) {
1592 selection.end = selection.start;
1593 } else {
1594 VisiblePosition visibleEnd(visibleSelection.visibleEnd());
1595 RenderedPosition renderedEnd(visibleEnd);
1596 renderedEnd.positionInGraphicsLayerBacking(selection.end);
1597 if (!selection.end.layer)
1598 return false;
1601 selection.type = visibleSelection.selectionType();
1602 selection.isEditable = visibleSelection.isContentEditable();
1603 if (selection.isEditable) {
1604 if (HTMLTextFormControlElement* enclosingTextFormControlElement = enclosingTextFormControl(visibleSelection.rootEditableElement()))
1605 selection.isEmptyTextFormControl = enclosingTextFormControlElement->value().isEmpty();
1607 selection.start.isTextDirectionRTL = primaryDirectionOf(*visibleSelection.start().anchorNode()) == RTL;
1608 selection.end.isTextDirectionRTL = primaryDirectionOf(*visibleSelection.end().anchorNode()) == RTL;
1610 return true;
1613 void FrameView::updateCompositedSelectionIfNeeded()
1615 if (!RuntimeEnabledFeatures::compositedSelectionUpdateEnabled())
1616 return;
1618 TRACE_EVENT0("blink", "FrameView::updateCompositedSelectionIfNeeded");
1620 Page* page = frame().page();
1621 ASSERT(page);
1623 CompositedSelection selection;
1624 Frame* focusedFrame = page->focusController().focusedOrMainFrame();
1625 LocalFrame* localFrame = focusedFrame->isLocalFrame() ? toLocalFrame(focusedFrame) : nullptr;
1626 if (!localFrame || !computeCompositedSelection(*localFrame, selection)) {
1627 page->chromeClient().clearCompositedSelection();
1628 return;
1631 page->chromeClient().updateCompositedSelection(selection);
1634 HostWindow* FrameView::hostWindow() const
1636 Page* page = frame().page();
1637 if (!page)
1638 return nullptr;
1639 return &page->chromeClient();
1642 void FrameView::contentRectangleForPaintInvalidation(const IntRect& rectInContent)
1644 ASSERT(!m_frame->ownerLayoutObject());
1646 IntRect paintRect = rectInContent;
1647 if (clipsPaintInvalidations())
1648 paintRect.intersect(visibleContentRect());
1649 if (paintRect.isEmpty())
1650 return;
1652 if (HostWindow* window = hostWindow())
1653 window->invalidateRect(contentsToRootFrame(paintRect));
1656 void FrameView::contentsResized()
1658 if (m_frame->isMainFrame() && m_frame->document()) {
1659 if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
1660 textAutosizer->updatePageInfoInAllFrames();
1663 ScrollableArea::contentsResized();
1664 setNeedsLayout();
1667 void FrameView::scrollbarExistenceDidChange()
1669 // We check to make sure the view is attached to a frame() as this method can
1670 // be triggered before the view is attached by LocalFrame::createView(...) setting
1671 // various values such as setScrollBarModes(...) for example. An ASSERT is
1672 // triggered when a view is layout before being attached to a frame().
1673 if (!frame().view())
1674 return;
1676 bool hasOverlayScrollbars = this->hasOverlayScrollbars();
1678 // FIXME: this call to layout() could be called within FrameView::layout(), but before performLayout(),
1679 // causing double-layout. See also crbug.com/429242.
1680 if (!hasOverlayScrollbars && needsLayout())
1681 layout();
1683 if (layoutView() && layoutView()->usesCompositing()) {
1684 layoutView()->compositor()->frameViewScrollbarsExistenceDidChange();
1686 if (!hasOverlayScrollbars)
1687 layoutView()->compositor()->frameViewDidChangeSize();
1691 void FrameView::handleLoadCompleted()
1693 // Once loading has completed, allow autoSize one last opportunity to
1694 // reduce the size of the frame.
1695 if (m_autoSizeInfo)
1696 m_autoSizeInfo->autoSizeIfNeeded();
1698 // If there is a pending layout, the scroll anchor will be cleared when it finishes.
1699 if (!needsLayout())
1700 clearScrollAnchor();
1703 void FrameView::clearLayoutSubtreeRoot(const LayoutObject& root)
1705 m_layoutSubtreeRootList.removeRoot(const_cast<LayoutObject&>(root));
1708 void FrameView::clearLayoutSubtreeRootsAndMarkContainingBlocks()
1710 m_layoutSubtreeRootList.clearAndMarkContainingBlocksForLayout();
1713 void FrameView::scheduleRelayout()
1715 ASSERT(m_frame->view() == this);
1717 if (!m_layoutSchedulingEnabled)
1718 return;
1719 if (!needsLayout())
1720 return;
1721 if (!m_frame->document()->shouldScheduleLayout())
1722 return;
1723 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", TRACE_EVENT_SCOPE_THREAD, "data", InspectorInvalidateLayoutEvent::data(m_frame.get()));
1725 clearLayoutSubtreeRootsAndMarkContainingBlocks();
1727 if (m_hasPendingLayout)
1728 return;
1729 m_hasPendingLayout = true;
1731 page()->animator().scheduleVisualUpdate(m_frame.get());
1732 lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1735 void FrameView::scheduleRelayoutOfSubtree(LayoutObject* relayoutRoot)
1737 ASSERT(m_frame->view() == this);
1739 // FIXME: Should this call shouldScheduleLayout instead?
1740 if (!m_frame->document()->isActive())
1741 return;
1743 LayoutView* layoutView = this->layoutView();
1744 if (layoutView && layoutView->needsLayout()) {
1745 if (relayoutRoot)
1746 relayoutRoot->markContainerChainForLayout(false);
1747 return;
1750 if (relayoutRoot == layoutView)
1751 m_layoutSubtreeRootList.clearAndMarkContainingBlocksForLayout();
1752 else
1753 m_layoutSubtreeRootList.addRoot(*relayoutRoot);
1755 if (m_layoutSchedulingEnabled) {
1756 m_hasPendingLayout = true;
1758 page()->animator().scheduleVisualUpdate(m_frame.get());
1759 lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1761 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", TRACE_EVENT_SCOPE_THREAD, "data", InspectorInvalidateLayoutEvent::data(m_frame.get()));
1764 bool FrameView::layoutPending() const
1766 // FIXME: This should check Document::lifecycle instead.
1767 return m_hasPendingLayout;
1770 bool FrameView::isInPerformLayout() const
1772 ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1773 return m_inPerformLayout;
1776 bool FrameView::needsLayout() const
1778 // This can return true in cases where the document does not have a body yet.
1779 // Document::shouldScheduleLayout takes care of preventing us from scheduling
1780 // layout in that case.
1782 LayoutView* layoutView = this->layoutView();
1783 return layoutPending()
1784 || (layoutView && layoutView->needsLayout())
1785 || isSubtreeLayout();
1788 void FrameView::setNeedsLayout()
1790 LayoutBox* box = embeddedContentBox();
1791 // It's illegal to ask for layout changes during the layout compositing or paint invalidation step.
1792 // FIXME: the third conditional is a hack to support embedded SVG. See FrameView::forceLayoutParentViewIfNeeded and crbug.com/442939
1793 RELEASE_ASSERT(!m_frame->document() || m_frame->document()->lifecycle().stateAllowsLayoutInvalidation() || (box && box->isSVGRoot()));
1795 if (LayoutView* layoutView = this->layoutView())
1796 layoutView->setNeedsLayout(LayoutInvalidationReason::Unknown);
1799 bool FrameView::isTransparent() const
1801 return m_isTransparent;
1804 void FrameView::setTransparent(bool isTransparent)
1806 m_isTransparent = isTransparent;
1807 DisableCompositingQueryAsserts disabler;
1808 if (layoutView() && layoutView()->layer()->hasCompositedDeprecatedPaintLayerMapping())
1809 layoutView()->layer()->compositedDeprecatedPaintLayerMapping()->updateContentsOpaque();
1812 bool FrameView::hasOpaqueBackground() const
1814 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1817 Color FrameView::baseBackgroundColor() const
1819 return m_baseBackgroundColor;
1822 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1824 m_baseBackgroundColor = backgroundColor;
1826 if (layoutView() && layoutView()->layer()->hasCompositedDeprecatedPaintLayerMapping()) {
1827 CompositedDeprecatedPaintLayerMapping* compositedDeprecatedPaintLayerMapping = layoutView()->layer()->compositedDeprecatedPaintLayerMapping();
1828 compositedDeprecatedPaintLayerMapping->updateContentsOpaque();
1829 if (compositedDeprecatedPaintLayerMapping->mainGraphicsLayer())
1830 compositedDeprecatedPaintLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1832 recalculateScrollbarOverlayStyle();
1835 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1837 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1838 if (!frame->isLocalFrame())
1839 continue;
1840 if (FrameView* view = toLocalFrame(frame)->view()) {
1841 view->setTransparent(transparent);
1842 view->setBaseBackgroundColor(backgroundColor);
1847 void FrameView::scrollToAnchor()
1849 RefPtrWillBeRawPtr<Node> anchorNode = m_scrollAnchor;
1850 if (!anchorNode)
1851 return;
1853 if (!anchorNode->layoutObject())
1854 return;
1856 // Scrolling is disabled during updateScrollbars (see isProgrammaticallyScrollable).
1857 // Bail now to avoid clearing m_scrollAnchor before we actually have a chance to scroll.
1858 if (m_inUpdateScrollbars)
1859 return;
1861 LayoutRect rect;
1862 if (anchorNode != m_frame->document()) {
1863 rect = anchorNode->boundingBox();
1864 } else if (m_frame->settings() && m_frame->settings()->rootLayerScrolls()) {
1865 if (Element* documentElement = m_frame->document()->documentElement())
1866 rect = documentElement->boundingBox();
1869 RefPtrWillBeRawPtr<Frame> boundaryFrame = m_frame->findUnsafeParentScrollPropagationBoundary();
1871 // FIXME: Handle RemoteFrames
1872 if (boundaryFrame && boundaryFrame->isLocalFrame())
1873 toLocalFrame(boundaryFrame.get())->view()->setSafeToPropagateScrollToParent(false);
1875 // Scroll nested layers and frames to reveal the anchor.
1876 // Align to the top and to the closest side (this matches other browsers).
1877 anchorNode->layoutObject()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1879 if (boundaryFrame && boundaryFrame->isLocalFrame())
1880 toLocalFrame(boundaryFrame.get())->view()->setSafeToPropagateScrollToParent(true);
1882 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1883 cache->handleScrolledToAnchor(anchorNode.get());
1885 // The scroll anchor should only be maintained while the frame is still loading.
1886 // If the frame is done loading, clear the anchor now. Otherwise, restore it
1887 // since it may have been cleared during scrollRectToVisible.
1888 m_scrollAnchor = m_frame->document()->isLoadCompleted() ? nullptr : anchorNode;
1891 bool FrameView::updateWidgets()
1893 // This is always called from updateWidgetsTimerFired.
1894 // m_updateWidgetsTimer should only be scheduled if we have widgets to update.
1895 // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty:
1896 // FIXME: This assert has been temporarily removed due to https://crbug.com/430344
1897 if (m_nestedLayoutCount > 1 || m_partUpdateSet.isEmpty())
1898 return true;
1900 // Need to swap because script will run inside the below loop and invalidate the iterator.
1901 EmbeddedObjectSet objects;
1902 objects.swap(m_partUpdateSet);
1904 for (const auto& embeddedObject : objects) {
1905 LayoutEmbeddedObject& object = *embeddedObject;
1906 HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
1908 // The object may have already been destroyed (thus node cleared),
1909 // but FrameView holds a manual ref, so it won't have been deleted.
1910 if (!element)
1911 continue;
1913 // No need to update if it's already crashed or known to be missing.
1914 if (object.showsUnavailablePluginIndicator())
1915 continue;
1917 if (element->needsWidgetUpdate())
1918 element->updateWidget();
1919 object.updateWidgetPosition();
1921 // Prevent plugins from causing infinite updates of themselves.
1922 // FIXME: Do we really need to prevent this?
1923 m_partUpdateSet.remove(&object);
1926 return m_partUpdateSet.isEmpty();
1929 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
1931 ASSERT(!isInPerformLayout());
1932 RefPtrWillBeRawPtr<FrameView> protect(this);
1933 m_updateWidgetsTimer.stop();
1934 for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
1935 if (updateWidgets())
1936 return;
1940 void FrameView::flushAnyPendingPostLayoutTasks()
1942 ASSERT(!isInPerformLayout());
1943 if (m_postLayoutTasksTimer.isActive())
1944 performPostLayoutTasks();
1945 if (m_updateWidgetsTimer.isActive())
1946 updateWidgetsTimerFired(0);
1949 void FrameView::scheduleUpdateWidgetsIfNecessary()
1951 ASSERT(!isInPerformLayout());
1952 if (m_updateWidgetsTimer.isActive() || m_partUpdateSet.isEmpty())
1953 return;
1954 m_updateWidgetsTimer.startOneShot(0, FROM_HERE);
1957 void FrameView::performPostLayoutTasks()
1959 // FIXME: We can reach here, even when the page is not active!
1960 // http/tests/inspector/elements/html-link-import.html and many other
1961 // tests hit that case.
1962 // We should ASSERT(isActive()); or at least return early if we can!
1963 ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
1964 TRACE_EVENT0("blink,benchmark", "FrameView::performPostLayoutTasks");
1965 RefPtrWillBeRawPtr<FrameView> protect(this);
1967 m_postLayoutTasksTimer.stop();
1969 m_frame->selection().setCaretRectNeedsUpdate();
1970 m_frame->selection().updateAppearance();
1972 ASSERT(m_frame->document());
1974 FontFaceSet::didLayout(*m_frame->document());
1975 // Cursor update scheduling is done by the local root, which is the main frame if there
1976 // are no RemoteFrame ancestors in the frame tree. Use of localFrameRoot() is
1977 // discouraged but will change when cursor update scheduling is moved from EventHandler
1978 // to PageEventHandler.
1979 frame().localFrameRoot()->eventHandler().scheduleCursorUpdate();
1981 updateWidgetPositions();
1983 // Plugins could have torn down the page inside updateWidgetPositions().
1984 if (!layoutView())
1985 return;
1987 scheduleUpdateWidgetsIfNecessary();
1989 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
1990 scrollingCoordinator->notifyLayoutUpdated();
1992 scrollToAnchor();
1994 sendResizeEventIfNeeded();
1997 bool FrameView::wasViewportResized()
1999 ASSERT(m_frame);
2000 LayoutView* layoutView = this->layoutView();
2001 if (!layoutView)
2002 return false;
2003 ASSERT(layoutView->style());
2004 return (layoutSize(IncludeScrollbars) != m_lastViewportSize || layoutView->style()->zoom() != m_lastZoomFactor);
2007 void FrameView::sendResizeEventIfNeeded()
2009 ASSERT(m_frame);
2011 LayoutView* layoutView = this->layoutView();
2012 if (!layoutView || layoutView->document().printing())
2013 return;
2015 if (!wasViewportResized())
2016 return;
2018 m_lastViewportSize = layoutSize(IncludeScrollbars);
2019 m_lastZoomFactor = layoutView->style()->zoom();
2021 m_frame->document()->enqueueResizeEvent();
2023 if (m_frame->isMainFrame())
2024 InspectorInstrumentation::didResizeMainFrame(m_frame.get());
2027 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2029 performPostLayoutTasks();
2032 void FrameView::updateCounters()
2034 LayoutView* view = layoutView();
2035 if (!view->hasLayoutCounters())
2036 return;
2038 for (LayoutObject* layoutObject = view; layoutObject; layoutObject = layoutObject->nextInPreOrder()) {
2039 if (!layoutObject->isCounter())
2040 continue;
2042 toLayoutCounter(layoutObject)->updateCounter();
2046 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const
2048 ASSERT(m_frame->view() == this);
2050 // Set our clip rect to be our contents.
2051 IntRect clipRect = contentsToRootFrame(visibleContentRect(scrollbarInclusion));
2052 if (!m_frame->deprecatedLocalOwner())
2053 return clipRect;
2055 // Take our owner element and get its clip rect.
2056 // FIXME: Do we need to do this for remote frames?
2057 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
2058 FrameView* parentView = ownerElement->document().view();
2059 if (parentView)
2060 clipRect.intersect(parentView->clipRectsForFrameOwner(ownerElement, nullptr));
2061 return clipRect;
2064 IntRect FrameView::clipRectsForFrameOwner(const HTMLFrameOwnerElement* ownerElement, IntRect* unobscuredRect) const
2066 ASSERT(ownerElement);
2068 if (unobscuredRect)
2069 *unobscuredRect = IntRect();
2071 // The layoutObject can sometimes be null when style="display:none" interacts
2072 // with external content and plugins.
2073 if (!ownerElement->layoutObject())
2074 return windowClipRect();
2076 // If we have no layer, just return our window clip rect.
2077 const DeprecatedPaintLayer* enclosingLayer = ownerElement->layoutObject()->enclosingLayer();
2078 if (!enclosingLayer)
2079 return windowClipRect();
2081 // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2082 // https://code.google.com/p/chromium/issues/detail?id=343769
2083 DisableCompositingQueryAsserts disabler;
2085 // Apply the clip from the layer.
2086 IntRect elementRect = contentsToRootFrame(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
2088 if (unobscuredRect) {
2089 *unobscuredRect = elementRect;
2091 // If element is not in root frame, clip to the local frame.
2092 // FIXME: Do we need to do this for remote frames?
2093 if (m_frame->deprecatedLocalOwner())
2094 unobscuredRect->intersect(contentsToRootFrame(visibleContentRect()));
2097 return intersection(elementRect, windowClipRect());
2100 bool FrameView::shouldUseIntegerScrollOffset() const
2102 if (m_frame->settings() && !m_frame->settings()->preferCompositingToLCDTextEnabled())
2103 return true;
2105 return ScrollableArea::shouldUseIntegerScrollOffset();
2108 bool FrameView::isActive() const
2110 Page* page = frame().page();
2111 return page && page->focusController().isActive();
2114 void FrameView::scrollTo(const DoublePoint& newPosition)
2116 DoublePoint oldPosition = m_scrollPosition;
2117 DoubleSize scrollDelta = newPosition - oldPosition;
2118 if (scrollDelta.isZero())
2119 return;
2121 if (m_frame->settings() && m_frame->settings()->rootLayerScrolls()) {
2122 // Don't scroll the FrameView!
2123 ASSERT_NOT_REACHED();
2126 m_scrollPosition = newPosition;
2128 if (!scrollbarsSuppressed())
2129 m_pendingScrollDelta += scrollDelta;
2131 clearScrollAnchor();
2132 updateLayersAndCompositingAfterScrollIfNeeded();
2133 scrollPositionChanged();
2134 frame().loader().client()->didChangeScrollOffset();
2137 void FrameView::invalidatePaintForTickmarks() const
2139 if (Scrollbar* scrollbar = verticalScrollbar())
2140 scrollbar->invalidate();
2143 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2145 // Add in our offset within the FrameView.
2146 IntRect dirtyRect = rect;
2147 dirtyRect.moveBy(scrollbar->location());
2149 layoutView()->invalidateDisplayItemClient(*scrollbar);
2151 if (isInPerformLayout())
2152 addScrollbarDamage(scrollbar, rect);
2153 else
2154 invalidateRect(dirtyRect);
2157 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2159 if (!m_tickmarks.isEmpty())
2160 tickmarks = m_tickmarks;
2161 else
2162 tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch);
2165 IntRect FrameView::windowResizerRect() const
2167 if (Page* page = frame().page())
2168 return page->chromeClient().windowResizerRect();
2169 return IntRect();
2172 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2174 m_inputEventsOffsetForEmulation = offset;
2175 m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2178 IntSize FrameView::inputEventsOffsetForEmulation() const
2180 return m_inputEventsOffsetForEmulation;
2183 float FrameView::inputEventsScaleFactor() const
2185 float pageScale = m_frame->host()->visualViewport().scale();
2186 return pageScale * m_inputEventsScaleFactorForEmulation;
2189 bool FrameView::scrollbarsCanBeActive() const
2191 if (m_frame->view() != this)
2192 return false;
2194 return !!m_frame->document();
2197 void FrameView::scrollbarVisibilityChanged()
2199 if (LayoutView* view = layoutView())
2200 view->clearHitTestCache();
2203 IntRect FrameView::scrollableAreaBoundingBox() const
2205 LayoutPart* ownerLayoutObject = frame().ownerLayoutObject();
2206 if (!ownerLayoutObject)
2207 return frameRect();
2209 return ownerLayoutObject->absoluteContentQuad().enclosingBoundingBox();
2213 bool FrameView::isScrollable()
2215 return scrollingReasons() == Scrollable;
2218 bool FrameView::isProgrammaticallyScrollable()
2220 return !m_inUpdateScrollbars;
2223 FrameView::ScrollingReasons FrameView::scrollingReasons()
2225 // Check for:
2226 // 1) If there an actual overflow.
2227 // 2) display:none or visibility:hidden set to self or inherited.
2228 // 3) overflow{-x,-y}: hidden;
2229 // 4) scrolling: no;
2231 // Covers #1
2232 IntSize contentsSize = this->contentsSize();
2233 IntSize visibleContentSize = visibleContentRect().size();
2234 if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2235 return NotScrollableNoOverflow;
2237 // Covers #2.
2238 // FIXME: Do we need to fix this for OOPI?
2239 HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
2240 if (owner && (!owner->layoutObject() || !owner->layoutObject()->visibleToHitTesting()))
2241 return NotScrollableNotVisible;
2243 // Cover #3 and #4.
2244 ScrollbarMode horizontalMode;
2245 ScrollbarMode verticalMode;
2246 calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly);
2247 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2248 return NotScrollableExplicitlyDisabled;
2250 return Scrollable;
2253 void FrameView::updateScrollableAreaSet()
2255 // That ensures that only inner frames are cached.
2256 FrameView* parentFrameView = this->parentFrameView();
2257 if (!parentFrameView)
2258 return;
2260 if (!isScrollable()) {
2261 parentFrameView->removeScrollableArea(this);
2262 return;
2265 parentFrameView->addScrollableArea(this);
2268 bool FrameView::shouldSuspendScrollAnimations() const
2270 return !m_frame->document()->loadEventFinished();
2273 void FrameView::scrollbarStyleChanged()
2275 // FIXME: Why does this only apply to the main frame?
2276 if (!m_frame->isMainFrame())
2277 return;
2278 adjustScrollbarOpacity();
2279 contentsResized();
2280 updateScrollbars(scrollOffsetDouble());
2281 positionScrollbarLayers();
2284 void FrameView::notifyPageThatContentAreaWillPaint() const
2286 Page* page = m_frame->page();
2287 if (!page)
2288 return;
2290 contentAreaWillPaint();
2292 if (!m_scrollableAreas)
2293 return;
2295 for (const auto& scrollableArea : *m_scrollableAreas) {
2296 if (!scrollableArea->scrollbarsCanBeActive())
2297 continue;
2299 scrollableArea->contentAreaWillPaint();
2303 bool FrameView::scrollAnimatorEnabled() const
2305 return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled();
2308 void FrameView::updateAnnotatedRegions()
2310 Document* document = m_frame->document();
2311 if (!document->hasAnnotatedRegions())
2312 return;
2313 Vector<AnnotatedRegionValue> newRegions;
2314 collectAnnotatedRegions(*(document->layoutBox()), newRegions);
2315 if (newRegions == document->annotatedRegions())
2316 return;
2317 document->setAnnotatedRegions(newRegions);
2318 if (Page* page = m_frame->page())
2319 page->chromeClient().annotatedRegionsChanged();
2322 void FrameView::updateScrollCorner()
2324 RefPtr<ComputedStyle> cornerStyle;
2325 IntRect cornerRect = scrollCornerRect();
2326 Document* doc = m_frame->document();
2328 if (doc && !cornerRect.isEmpty()) {
2329 // Try the <body> element first as a scroll corner source.
2330 if (Element* body = doc->body()) {
2331 if (LayoutObject* layoutObject = body->layoutObject())
2332 cornerStyle = layoutObject->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), layoutObject->style());
2335 if (!cornerStyle) {
2336 // If the <body> didn't have a custom style, then the root element might.
2337 if (Element* docElement = doc->documentElement()) {
2338 if (LayoutObject* layoutObject = docElement->layoutObject())
2339 cornerStyle = layoutObject->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), layoutObject->style());
2343 if (!cornerStyle) {
2344 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
2345 if (LayoutPart* layoutObject = m_frame->ownerLayoutObject())
2346 cornerStyle = layoutObject->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), layoutObject->style());
2350 if (cornerStyle) {
2351 if (!m_scrollCorner)
2352 m_scrollCorner = LayoutScrollbarPart::createAnonymous(doc);
2353 m_scrollCorner->setStyle(cornerStyle.release());
2354 invalidateScrollCorner(cornerRect);
2355 } else if (m_scrollCorner) {
2356 m_scrollCorner->destroy();
2357 m_scrollCorner = nullptr;
2361 Color FrameView::documentBackgroundColor() const
2363 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2364 // the document and the body against the base background color of the frame view.
2365 // Background images are unfortunately impractical to include.
2367 Color result = baseBackgroundColor();
2368 if (!frame().document())
2369 return result;
2371 Element* htmlElement = frame().document()->documentElement();
2372 Element* bodyElement = frame().document()->body();
2374 // We take the aggregate of the base background color
2375 // the <html> background color, and the <body>
2376 // background color to find the document color. The
2377 // addition of the base background color is not
2378 // technically part of the document background, but it
2379 // otherwise poses problems when the aggregate is not
2380 // fully opaque.
2381 if (htmlElement && htmlElement->layoutObject())
2382 result = result.blend(htmlElement->layoutObject()->resolveColor(CSSPropertyBackgroundColor));
2383 if (bodyElement && bodyElement->layoutObject())
2384 result = result.blend(bodyElement->layoutObject()->resolveColor(CSSPropertyBackgroundColor));
2386 return result;
2389 FrameView* FrameView::parentFrameView() const
2391 if (!parent())
2392 return nullptr;
2394 Frame* parentFrame = m_frame->tree().parent();
2395 if (parentFrame && parentFrame->isLocalFrame())
2396 return toLocalFrame(parentFrame)->view();
2398 return nullptr;
2401 bool FrameView::isPainting() const
2403 return m_isPainting;
2406 void FrameView::setNodeToDraw(Node* node)
2408 m_nodeToDraw = node;
2411 void FrameView::updateWidgetPositionsIfNeeded()
2413 if (!m_needsUpdateWidgetPositions)
2414 return;
2416 m_needsUpdateWidgetPositions = false;
2418 updateWidgetPositions();
2421 void FrameView::updateAllLifecyclePhases(const LayoutRect& interestRect)
2423 frame().localFrameRoot()->view()->updateLifecyclePhasesInternal(AllPhases, interestRect);
2426 // TODO(chrishtr): add a scrolling update lifecycle phase.
2427 void FrameView::updateLifecycleToCompositingCleanPlusScrolling()
2429 frame().localFrameRoot()->view()->updateLifecyclePhasesInternal(OnlyUpToCompositingCleanPlusScrolling);
2432 void FrameView::updateLifecyclePhasesInternal(LifeCycleUpdateOption phases, const LayoutRect& interestRect)
2434 // This must be called from the root frame, since it recurses down, not up.
2435 // Otherwise the lifecycles of the frames might be out of sync.
2436 ASSERT(m_frame->isLocalRoot());
2438 // Updating layout can run script, which can tear down the FrameView.
2439 RefPtrWillBeRawPtr<FrameView> protector(this);
2441 updateStyleAndLayoutIfNeededRecursive();
2443 if (LayoutView* view = layoutView()) {
2444 TRACE_EVENT1("devtools.timeline", "UpdateLayerTree", "data", InspectorUpdateLayerTreeEvent::data(m_frame.get()));
2446 // This was required for slimming paint v1 but is only temporarily
2447 // needed for slimming paint v2.
2448 view->compositor()->updateIfNeededRecursive();
2449 scrollContentsIfNeededRecursive();
2451 ASSERT(lifecycle().state() >= DocumentLifecycle::CompositingClean);
2453 if (phases == AllPhases) {
2454 invalidateTreeIfNeededRecursive();
2456 if (view->compositor()->inCompositingMode())
2457 scrollingCoordinator()->updateAfterCompositingChangeIfNeeded();
2459 updateCompositedSelectionIfNeeded();
2461 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
2462 paintForSlimmingPaintV2(interestRect);
2463 compositeForSlimmingPaintV2();
2466 if (RuntimeEnabledFeatures::frameTimingSupportEnabled())
2467 updateFrameTimingRequestsIfNeeded();
2469 ASSERT(!view->hasPendingSelection());
2470 ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean
2471 || (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && lifecycle().state() == DocumentLifecycle::CompositingForSlimmingPaintV2Clean));
2476 void FrameView::paintForSlimmingPaintV2(const LayoutRect& interestRect)
2478 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
2479 ASSERT(frame() == page()->mainFrame() || (!frame().tree().parent()->isLocalFrame()));
2481 LayoutView* view = layoutView();
2482 ASSERT(view);
2483 GraphicsLayer* rootGraphicsLayer = view->layer()->graphicsLayerBacking();
2485 // Detached frames can have no root graphics layer.
2486 if (!rootGraphicsLayer)
2487 return;
2489 lifecycle().advanceTo(DocumentLifecycle::InPaintForSlimmingPaintV2);
2491 GraphicsContext context(rootGraphicsLayer->displayItemList());
2492 rootGraphicsLayer->paint(context, roundedIntRect(interestRect));
2494 lifecycle().advanceTo(DocumentLifecycle::PaintForSlimmingPaintV2Clean);
2497 void FrameView::compositeForSlimmingPaintV2()
2499 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
2500 ASSERT(frame() == page()->mainFrame() || (!frame().tree().parent()->isLocalFrame()));
2502 GraphicsLayer* rootGraphicsLayer = layoutView()->layer()->graphicsLayerBacking();
2504 // Detached frames can have no root graphics layer.
2505 if (!rootGraphicsLayer)
2506 return;
2508 lifecycle().advanceTo(DocumentLifecycle::InCompositingForSlimmingPaintV2);
2510 DisplayListDiff displayListDiff;
2511 rootGraphicsLayer->displayItemList()->commitNewDisplayItems(&displayListDiff);
2513 DisplayListCompositingBuilder compositingBuilder(*rootGraphicsLayer->displayItemList(), displayListDiff);
2514 OwnPtr<CompositedDisplayList> compositedDisplayList = adoptPtr(new CompositedDisplayList());
2515 compositingBuilder.build(*compositedDisplayList);
2516 page()->setCompositedDisplayList(compositedDisplayList.release());
2518 lifecycle().advanceTo(DocumentLifecycle::CompositingForSlimmingPaintV2Clean);
2521 void FrameView::updateFrameTimingRequestsIfNeeded()
2523 GraphicsLayerFrameTimingRequests graphicsLayerTimingRequests;
2524 // TODO(mpb) use a 'dirty' bit to not call this every time.
2525 collectFrameTimingRequestsRecursive(graphicsLayerTimingRequests);
2527 for (const auto& iter : graphicsLayerTimingRequests) {
2528 const GraphicsLayer* graphicsLayer = iter.key;
2529 graphicsLayer->platformLayer()->setFrameTimingRequests(iter.value);
2533 void FrameView::updateStyleAndLayoutIfNeededRecursive()
2535 // We have to crawl our entire subtree looking for any FrameViews that need
2536 // layout and make sure they are up to date.
2537 // Mac actually tests for intersection with the dirty region and tries not to
2538 // update layout for frames that are outside the dirty region. Not only does this seem
2539 // pointless (since those frames will have set a zero timer to layout anyway), but
2540 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2541 // region but then become included later by the second frame adding rects to the dirty region
2542 // when it lays out.
2544 m_frame->document()->updateLayoutTreeIfNeeded();
2546 if (needsLayout())
2547 layout();
2549 // FIXME: Calling layout() shouldn't trigger script execution or have any
2550 // observable effects on the frame tree but we're not quite there yet.
2551 WillBeHeapVector<RefPtrWillBeMember<FrameView>> frameViews;
2552 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2553 if (!child->isLocalFrame())
2554 continue;
2555 if (FrameView* view = toLocalFrame(child)->view())
2556 frameViews.append(view);
2559 for (const auto& frameView : frameViews)
2560 frameView->updateStyleAndLayoutIfNeededRecursive();
2562 // When an <iframe> gets composited, it triggers an extra style recalc in its containing FrameView.
2563 // To avoid pushing an invalid tree for display, we have to check for this case and do another
2564 // style recalc. The extra style recalc needs to happen after our child <iframes> were updated.
2565 // FIXME: We shouldn't be triggering an extra style recalc in the first place.
2566 if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) {
2567 m_frame->document()->updateLayoutTreeIfNeeded();
2569 if (needsLayout())
2570 layout();
2573 // These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
2574 ASSERT(!needsLayout());
2575 ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate());
2576 #if ENABLE(ASSERT)
2577 m_frame->document()->layoutView()->assertLaidOut();
2578 #endif
2580 updateWidgetPositionsIfNeeded();
2583 void FrameView::invalidateTreeIfNeededRecursive()
2585 ASSERT(layoutView());
2586 TRACE_EVENT1("blink", "FrameView::invalidateTreeIfNeededRecursive", "root", layoutView()->debugName().ascii());
2588 Vector<LayoutObject*> pendingDelayedPaintInvalidations;
2589 PaintInvalidationState rootPaintInvalidationState(*layoutView(), pendingDelayedPaintInvalidations);
2591 invalidateTreeIfNeeded(rootPaintInvalidationState);
2593 // Some frames may be not reached during the above invalidateTreeIfNeeded because
2594 // - the frame is a detached frame; or
2595 // - it didn't need paint invalidation.
2596 // We need to call invalidateTreeIfNeededRecursive() for such frames to finish required
2597 // paint invalidation and advance their life cycle state.
2598 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2599 if (!child->isLocalFrame())
2600 continue;
2601 FrameView* childFrameView = toLocalFrame(child)->view();
2602 if (childFrameView->lifecycle().state() < DocumentLifecycle::PaintInvalidationClean)
2603 childFrameView->invalidateTreeIfNeededRecursive();
2606 // Process objects needing paint invalidation on the next frame. See the definition of PaintInvalidationDelayedFull for more details.
2607 for (auto& target : pendingDelayedPaintInvalidations)
2608 target->setShouldDoFullPaintInvalidation(PaintInvalidationDelayedFull);
2611 void FrameView::enableAutoSizeMode(const IntSize& minSize, const IntSize& maxSize)
2613 if (!m_autoSizeInfo)
2614 m_autoSizeInfo = FrameViewAutoSizeInfo::create(this);
2616 m_autoSizeInfo->configureAutoSizeMode(minSize, maxSize);
2617 setLayoutSizeFixedToFrameSize(true);
2618 setNeedsLayout();
2619 scheduleRelayout();
2622 void FrameView::disableAutoSizeMode()
2624 if (!m_autoSizeInfo)
2625 return;
2627 setLayoutSizeFixedToFrameSize(false);
2628 setNeedsLayout();
2629 scheduleRelayout();
2631 // Since autosize mode forces the scrollbar mode, change them to being auto.
2632 setVerticalScrollbarLock(false);
2633 setHorizontalScrollbarLock(false);
2634 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
2635 m_autoSizeInfo.clear();
2638 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2640 // Dumping externalRepresentation(m_frame->layoutObject()).ascii() is a good trick to see
2641 // the state of things before and after the layout
2642 if (LayoutView* layoutView = this->layoutView()) {
2643 float pageLogicalWidth = layoutView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2644 float pageLogicalHeight = layoutView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2646 LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2647 LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2648 layoutView->setLogicalWidth(flooredPageLogicalWidth);
2649 layoutView->setPageLogicalHeight(flooredPageLogicalHeight);
2650 layoutView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::PrintingChanged);
2651 layout();
2653 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2654 // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2655 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
2656 // implementation should not do this!
2657 bool horizontalWritingMode = layoutView->style()->isHorizontalWritingMode();
2658 const LayoutRect& documentRect = LayoutRect(layoutView->documentRect());
2659 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2660 if (docLogicalWidth > pageLogicalWidth) {
2661 FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor));
2662 FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize);
2663 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2664 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2666 flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2667 flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2668 layoutView->setLogicalWidth(flooredPageLogicalWidth);
2669 layoutView->setPageLogicalHeight(flooredPageLogicalHeight);
2670 layoutView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::PrintingChanged);
2671 layout();
2673 const LayoutRect& updatedDocumentRect = LayoutRect(layoutView->documentRect());
2674 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2675 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2676 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2677 LayoutUnit clippedLogicalLeft = 0;
2678 if (!layoutView->style()->isLeftToRightDirection())
2679 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2680 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2682 if (!horizontalWritingMode)
2683 overflow = overflow.transposedRect();
2684 layoutView->clearLayoutOverflow();
2685 layoutView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2689 adjustViewSize();
2692 IntRect FrameView::convertFromLayoutObject(const LayoutObject& layoutObject, const IntRect& layoutObjectRect) const
2694 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(layoutObject.localToAbsoluteQuad(FloatRect(layoutObjectRect)).boundingBox()));
2696 // Convert from page ("absolute") to FrameView coordinates.
2697 rect.moveBy(-scrollPosition());
2699 return rect;
2702 IntRect FrameView::convertToLayoutObject(const LayoutObject& layoutObject, const IntRect& frameRect) const
2704 IntRect rectInContent = frameToContents(frameRect);
2706 // Convert from FrameView coords into page ("absolute") coordinates.
2707 rectInContent.moveBy(scrollPosition());
2709 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2710 // move the rect for now.
2711 rectInContent.setLocation(roundedIntPoint(layoutObject.absoluteToLocal(rectInContent.location(), UseTransforms)));
2712 return rectInContent;
2715 IntPoint FrameView::convertFromLayoutObject(const LayoutObject& layoutObject, const IntPoint& layoutObjectPoint) const
2717 IntPoint point = roundedIntPoint(layoutObject.localToAbsolute(layoutObjectPoint, UseTransforms));
2719 // Convert from page ("absolute") to FrameView coordinates.
2720 point.moveBy(-scrollPosition());
2721 return point;
2724 IntPoint FrameView::convertToLayoutObject(const LayoutObject& layoutObject, const IntPoint& framePoint) const
2726 IntPoint point = framePoint;
2728 // Convert from FrameView coords into page ("absolute") coordinates.
2729 point += IntSize(scrollX(), scrollY());
2731 return roundedIntPoint(layoutObject.absoluteToLocal(point, UseTransforms));
2734 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2736 if (const FrameView* parentView = toFrameView(parent())) {
2737 // Get our layoutObject in the parent view
2738 LayoutPart* layoutObject = m_frame->ownerLayoutObject();
2739 if (!layoutObject)
2740 return localRect;
2742 IntRect rect(localRect);
2743 // Add borders and padding??
2744 rect.move(layoutObject->borderLeft() + layoutObject->paddingLeft(),
2745 layoutObject->borderTop() + layoutObject->paddingTop());
2746 return parentView->convertFromLayoutObject(*layoutObject, rect);
2749 return localRect;
2752 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
2754 if (const FrameView* parentView = toFrameView(parent())) {
2755 // Get our layoutObject in the parent view
2756 LayoutPart* layoutObject = m_frame->ownerLayoutObject();
2757 if (!layoutObject)
2758 return parentRect;
2760 IntRect rect = parentView->convertToLayoutObject(*layoutObject, parentRect);
2761 // Subtract borders and padding
2762 rect.move(-layoutObject->borderLeft() - layoutObject->paddingLeft(),
2763 -layoutObject->borderTop() - layoutObject->paddingTop());
2764 return rect;
2767 return parentRect;
2770 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
2772 if (const FrameView* parentView = toFrameView(parent())) {
2773 // Get our layoutObject in the parent view
2774 LayoutPart* layoutObject = m_frame->ownerLayoutObject();
2775 if (!layoutObject)
2776 return localPoint;
2778 IntPoint point(localPoint);
2780 // Add borders and padding
2781 point.move(layoutObject->borderLeft() + layoutObject->paddingLeft(),
2782 layoutObject->borderTop() + layoutObject->paddingTop());
2783 return parentView->convertFromLayoutObject(*layoutObject, point);
2786 return localPoint;
2789 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
2791 if (const FrameView* parentView = toFrameView(parent())) {
2792 // Get our layoutObject in the parent view
2793 LayoutPart* layoutObject = m_frame->ownerLayoutObject();
2794 if (!layoutObject)
2795 return parentPoint;
2797 IntPoint point = parentView->convertToLayoutObject(*layoutObject, parentPoint);
2798 // Subtract borders and padding
2799 point.move(-layoutObject->borderLeft() - layoutObject->paddingLeft(),
2800 -layoutObject->borderTop() - layoutObject->paddingTop());
2801 return point;
2804 return parentPoint;
2807 void FrameView::setInitialTracksPaintInvalidationsForTesting(bool trackPaintInvalidations)
2809 s_initialTrackAllPaintInvalidations = trackPaintInvalidations;
2812 void FrameView::setTracksPaintInvalidations(bool trackPaintInvalidations)
2814 if (trackPaintInvalidations == m_isTrackingPaintInvalidations)
2815 return;
2817 for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
2818 if (!frame->isLocalFrame())
2819 continue;
2820 if (LayoutView* layoutView = toLocalFrame(frame)->contentLayoutObject())
2821 layoutView->compositor()->setTracksPaintInvalidations(trackPaintInvalidations);
2824 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
2825 "FrameView::setTracksPaintInvalidations", TRACE_EVENT_SCOPE_GLOBAL, "enabled", trackPaintInvalidations);
2827 resetTrackedPaintInvalidations();
2828 m_isTrackingPaintInvalidations = trackPaintInvalidations;
2831 void FrameView::resetTrackedPaintInvalidations()
2833 if (LayoutView* layoutView = this->layoutView())
2834 layoutView->compositor()->resetTrackedPaintInvalidationRects();
2837 void FrameView::addResizerArea(LayoutBox& resizerBox)
2839 if (!m_resizerAreas)
2840 m_resizerAreas = adoptPtr(new ResizerAreaSet);
2841 m_resizerAreas->add(&resizerBox);
2844 void FrameView::removeResizerArea(LayoutBox& resizerBox)
2846 if (!m_resizerAreas)
2847 return;
2849 ResizerAreaSet::iterator it = m_resizerAreas->find(&resizerBox);
2850 if (it != m_resizerAreas->end())
2851 m_resizerAreas->remove(it);
2854 void FrameView::addScrollableArea(ScrollableArea* scrollableArea)
2856 ASSERT(scrollableArea);
2857 if (!m_scrollableAreas)
2858 m_scrollableAreas = adoptPtrWillBeNoop(new ScrollableAreaSet);
2859 m_scrollableAreas->add(scrollableArea);
2861 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
2862 scrollingCoordinator->scrollableAreasDidChange();
2865 void FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
2867 if (!m_scrollableAreas)
2868 return;
2869 m_scrollableAreas->remove(scrollableArea);
2871 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
2872 scrollingCoordinator->scrollableAreasDidChange();
2875 void FrameView::addAnimatingScrollableArea(ScrollableArea* scrollableArea)
2877 ASSERT(scrollableArea);
2878 if (!m_animatingScrollableAreas)
2879 m_animatingScrollableAreas = adoptPtrWillBeNoop(new ScrollableAreaSet);
2880 m_animatingScrollableAreas->add(scrollableArea);
2883 void FrameView::removeAnimatingScrollableArea(ScrollableArea* scrollableArea)
2885 if (!m_animatingScrollableAreas)
2886 return;
2887 m_animatingScrollableAreas->remove(scrollableArea);
2890 void FrameView::setParent(Widget* parentView)
2892 if (parentView == parent())
2893 return;
2895 if (m_scrollbarsAvoidingResizer && parent())
2896 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
2898 Widget::setParent(parentView);
2900 if (m_scrollbarsAvoidingResizer && parent())
2901 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
2903 updateScrollableAreaSet();
2906 void FrameView::removeChild(Widget* child)
2908 ASSERT(child->parent() == this);
2910 if (child->isFrameView())
2911 removeScrollableArea(toFrameView(child));
2913 child->setParent(0);
2914 m_children.remove(child);
2917 bool FrameView::isVerticalDocument() const
2919 LayoutView* layoutView = this->layoutView();
2920 if (!layoutView)
2921 return true;
2923 return layoutView->style()->isHorizontalWritingMode();
2926 bool FrameView::isFlippedDocument() const
2928 LayoutView* layoutView = this->layoutView();
2929 if (!layoutView)
2930 return false;
2932 return layoutView->hasFlippedBlocksWritingMode();
2935 bool FrameView::visualViewportSuppliesScrollbars() const
2937 return m_frame->isMainFrame() && m_frame->settings() && m_frame->settings()->viewportMetaEnabled();
2940 AXObjectCache* FrameView::axObjectCache() const
2942 if (frame().document())
2943 return frame().document()->existingAXObjectCache();
2944 return nullptr;
2947 void FrameView::setCursor(const Cursor& cursor)
2949 Page* page = frame().page();
2950 if (!page || !page->settings().deviceSupportsMouse())
2951 return;
2952 page->chromeClient().setCursor(cursor);
2955 void FrameView::frameRectsChanged()
2957 TRACE_EVENT0("blink", "FrameView::frameRectsChanged");
2958 if (layoutSizeFixedToFrameSize())
2959 setLayoutSizeInternal(frameRect().size());
2961 for (const auto& child : m_children)
2962 child->frameRectsChanged();
2965 void FrameView::setLayoutSizeInternal(const IntSize& size)
2967 if (m_layoutSize == size)
2968 return;
2970 m_layoutSize = size;
2972 if (Document* document = m_frame->document()) {
2973 if (document->isActive())
2974 document->notifyResizeForViewportUnits();
2977 contentsResized();
2980 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
2982 ScrollableArea::didAddScrollbar(scrollbar, orientation);
2983 if (AXObjectCache* cache = axObjectCache())
2984 cache->handleScrollbarUpdate(this);
2987 void FrameView::setTopControlsViewportAdjustment(float adjustment)
2989 m_topControlsViewportAdjustment = adjustment;
2992 IntPoint FrameView::maximumScrollPosition() const
2994 // Make the same calculation as in CC's LayerImpl::MaxScrollOffset()
2995 // FIXME: We probably shouldn't be storing the bounds in a float. crbug.com/422331.
2996 IntSize visibleSize = visibleContentSize(ExcludeScrollbars) + topControlsSize();
2997 IntSize contentBounds = contentsSize();
2998 IntPoint maximumPosition = -scrollOrigin() + (contentBounds - visibleSize);
2999 return maximumPosition.expandedTo(minimumScrollPosition());
3002 void FrameView::addChild(PassRefPtrWillBeRawPtr<Widget> prpChild)
3004 Widget* child = prpChild.get();
3005 ASSERT(child != this && !child->parent());
3006 child->setParent(this);
3007 m_children.add(prpChild);
3010 void FrameView::setHasHorizontalScrollbar(bool hasBar)
3012 if (hasBar == !!m_horizontalScrollbar)
3013 return;
3015 if (hasBar) {
3016 m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
3017 addChild(m_horizontalScrollbar.get());
3018 didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
3019 m_horizontalScrollbar->styleChanged();
3020 } else {
3021 willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar);
3022 if (AXObjectCache* cache = axObjectCache())
3023 cache->remove(m_horizontalScrollbar.get());
3024 // If the scrollbar has been marked as overlapping the window resizer,
3025 // then its removal should reduce the count.
3026 if (m_horizontalScrollbar->overlapsResizer())
3027 adjustScrollbarsAvoidingResizerCount(-1);
3028 removeChild(m_horizontalScrollbar.get());
3029 m_horizontalScrollbar->disconnectFromScrollableArea();
3030 m_horizontalScrollbar = nullptr;
3031 if (AXObjectCache* cache = axObjectCache())
3032 cache->handleScrollbarUpdate(this);
3035 invalidateScrollCorner(scrollCornerRect());
3038 void FrameView::setHasVerticalScrollbar(bool hasBar)
3040 if (hasBar == !!m_verticalScrollbar)
3041 return;
3043 if (hasBar) {
3044 m_verticalScrollbar = createScrollbar(VerticalScrollbar);
3045 addChild(m_verticalScrollbar.get());
3046 didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
3047 m_verticalScrollbar->styleChanged();
3048 } else {
3049 willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar);
3050 if (AXObjectCache* cache = axObjectCache())
3051 cache->remove(m_verticalScrollbar.get());
3052 // If the scrollbar has been marked as overlapping the window resizer,
3053 // then its removal should reduce the count.
3054 if (m_verticalScrollbar->overlapsResizer())
3055 adjustScrollbarsAvoidingResizerCount(-1);
3056 removeChild(m_verticalScrollbar.get());
3057 m_verticalScrollbar->disconnectFromScrollableArea();
3058 m_verticalScrollbar = nullptr;
3059 if (AXObjectCache* cache = axObjectCache())
3060 cache->handleScrollbarUpdate(this);
3063 invalidateScrollCorner(scrollCornerRect());
3066 void FrameView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
3067 bool horizontalLock, bool verticalLock)
3069 bool needsUpdate = false;
3071 // If the page's overflow setting has disabled scrolling, do not allow anything to override that setting.
3072 // http://crbug.com/426447
3073 LayoutObject* viewport = viewportLayoutObject();
3074 if (viewport && !shouldIgnoreOverflowHidden()) {
3075 if (viewport->style()->overflowX() == OHIDDEN)
3076 horizontalMode = ScrollbarAlwaysOff;
3077 if (viewport->style()->overflowY() == OHIDDEN)
3078 verticalMode = ScrollbarAlwaysOff;
3081 if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
3082 m_horizontalScrollbarMode = horizontalMode;
3083 needsUpdate = true;
3086 if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
3087 m_verticalScrollbarMode = verticalMode;
3088 needsUpdate = true;
3091 if (horizontalLock)
3092 setHorizontalScrollbarLock();
3094 if (verticalLock)
3095 setVerticalScrollbarLock();
3097 if (!needsUpdate)
3098 return;
3100 updateScrollbars(scrollOffsetDouble());
3102 if (!layerForScrolling())
3103 return;
3104 WebLayer* layer = layerForScrolling()->platformLayer();
3105 if (!layer)
3106 return;
3107 layer->setUserScrollable(userInputScrollable(HorizontalScrollbar), userInputScrollable(VerticalScrollbar));
3110 void FrameView::setClipsRepaints(bool clipsRepaints)
3112 m_clipsRepaints = clipsRepaints;
3115 IntSize FrameView::visibleContentSize(IncludeScrollbarsInRect scrollbarInclusion) const
3117 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(frameRect().size()) : frameRect().size();
3120 IntRect FrameView::visibleContentRect(IncludeScrollbarsInRect scrollbarInclusion) const
3122 return IntRect(flooredIntPoint(m_scrollPosition), visibleContentSize(scrollbarInclusion));
3125 IntSize FrameView::contentsSize() const
3127 return m_contentsSize;
3130 IntPoint FrameView::minimumScrollPosition() const
3132 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y());
3135 void FrameView::adjustScrollbarOpacity()
3137 if (m_horizontalScrollbar && layerForHorizontalScrollbar()) {
3138 bool isOpaqueScrollbar = !m_horizontalScrollbar->isOverlayScrollbar();
3139 layerForHorizontalScrollbar()->setContentsOpaque(isOpaqueScrollbar);
3141 if (m_verticalScrollbar && layerForVerticalScrollbar()) {
3142 bool isOpaqueScrollbar = !m_verticalScrollbar->isOverlayScrollbar();
3143 layerForVerticalScrollbar()->setContentsOpaque(isOpaqueScrollbar);
3147 int FrameView::scrollSize(ScrollbarOrientation orientation) const
3149 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
3151 // If no scrollbars are present, the content may still be scrollable.
3152 if (!scrollbar) {
3153 IntSize scrollSize = m_contentsSize - visibleContentRect().size();
3154 scrollSize.clampNegativeToZero();
3155 return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height();
3158 return scrollbar->totalSize() - scrollbar->visibleSize();
3161 void FrameView::setScrollOffset(const IntPoint& offset, ScrollType)
3163 scrollTo(clampScrollPosition(offset));
3166 void FrameView::setScrollOffset(const DoublePoint& offset, ScrollType)
3168 scrollTo(clampScrollPosition(offset));
3171 void FrameView::windowResizerRectChanged()
3173 updateScrollbars(scrollOffsetDouble());
3176 bool FrameView::hasOverlayScrollbars() const
3179 return (m_horizontalScrollbar && m_horizontalScrollbar->isOverlayScrollbar())
3180 || (m_verticalScrollbar && m_verticalScrollbar->isOverlayScrollbar());
3183 void FrameView::computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool& newHasVerticalScrollbar, const IntSize& docSize, ComputeScrollbarExistenceOption option) const
3185 bool hasHorizontalScrollbar = m_horizontalScrollbar;
3186 bool hasVerticalScrollbar = m_verticalScrollbar;
3188 newHasHorizontalScrollbar = hasHorizontalScrollbar;
3189 newHasVerticalScrollbar = hasVerticalScrollbar;
3191 if (m_frame->settings() && m_frame->settings()->rootLayerScrolls())
3192 return;
3194 ScrollbarMode hScroll = m_horizontalScrollbarMode;
3195 ScrollbarMode vScroll = m_verticalScrollbarMode;
3197 if (hScroll != ScrollbarAuto)
3198 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
3199 if (vScroll != ScrollbarAuto)
3200 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
3202 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto))
3203 return;
3205 if (hScroll == ScrollbarAuto)
3206 newHasHorizontalScrollbar = docSize.width() > visibleWidth();
3207 if (vScroll == ScrollbarAuto)
3208 newHasVerticalScrollbar = docSize.height() > visibleHeight();
3210 if (hasOverlayScrollbars())
3211 return;
3213 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size();
3215 bool attemptToRemoveScrollbars = (option == FirstPass
3216 && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height());
3217 if (attemptToRemoveScrollbars) {
3218 if (hScroll == ScrollbarAuto)
3219 newHasHorizontalScrollbar = false;
3220 if (vScroll == ScrollbarAuto)
3221 newHasVerticalScrollbar = false;
3225 void FrameView::updateScrollbarGeometry()
3227 if (m_horizontalScrollbar) {
3228 int clientWidth = visibleWidth();
3229 IntRect oldRect(m_horizontalScrollbar->frameRect());
3230 IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScrollbar) ? m_verticalScrollbar->width() : 0,
3231 height() - m_horizontalScrollbar->height(),
3232 width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
3233 m_horizontalScrollbar->height());
3234 m_horizontalScrollbar->setFrameRect(adjustScrollbarRectForResizer(hBarRect, m_horizontalScrollbar.get()));
3235 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
3236 m_horizontalScrollbar->invalidate();
3238 if (m_scrollbarsSuppressed)
3239 m_horizontalScrollbar->setSuppressInvalidation(true);
3240 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
3241 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
3242 m_horizontalScrollbar->offsetDidChange();
3243 if (m_scrollbarsSuppressed)
3244 m_horizontalScrollbar->setSuppressInvalidation(false);
3247 if (m_verticalScrollbar) {
3248 int clientHeight = visibleHeight();
3249 IntRect oldRect(m_verticalScrollbar->frameRect());
3250 IntRect vBarRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
3252 m_verticalScrollbar->width(),
3253 height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
3254 m_verticalScrollbar->setFrameRect(adjustScrollbarRectForResizer(vBarRect, m_verticalScrollbar.get()));
3255 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
3256 m_verticalScrollbar->invalidate();
3258 if (m_scrollbarsSuppressed)
3259 m_verticalScrollbar->setSuppressInvalidation(true);
3260 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
3261 m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
3262 m_verticalScrollbar->offsetDidChange();
3263 if (m_scrollbarsSuppressed)
3264 m_verticalScrollbar->setSuppressInvalidation(false);
3268 IntRect FrameView::adjustScrollbarRectForResizer(const IntRect& rect, Scrollbar* scrollbar)
3270 // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
3271 // if necessary.
3272 IntRect adjustedRect(rect);
3273 bool overlapsResizer = false;
3274 if (!rect.isEmpty() && !windowResizerRect().isEmpty()) {
3275 IntRect resizerRect = convertFromContainingWindow(windowResizerRect());
3276 if (rect.intersects(resizerRect)) {
3277 if (scrollbar->orientation() == HorizontalScrollbar) {
3278 int overlap = rect.maxX() - resizerRect.x();
3279 if (overlap > 0 && resizerRect.maxX() >= rect.maxX()) {
3280 adjustedRect.setWidth(rect.width() - overlap);
3281 overlapsResizer = true;
3283 } else {
3284 int overlap = rect.maxY() - resizerRect.y();
3285 if (overlap > 0 && resizerRect.maxY() >= rect.maxY()) {
3286 adjustedRect.setHeight(rect.height() - overlap);
3287 overlapsResizer = true;
3292 if (overlapsResizer != scrollbar->overlapsResizer()) {
3293 scrollbar->setOverlapsResizer(overlapsResizer);
3294 adjustScrollbarsAvoidingResizerCount(overlapsResizer ? 1 : -1);
3296 return adjustedRect;
3299 bool FrameView::adjustScrollbarExistence(ComputeScrollbarExistenceOption option)
3301 ASSERT(m_inUpdateScrollbars);
3303 // If we came in here with the view already needing a layout, then go ahead and do that
3304 // first. (This will be the common case, e.g., when the page changes due to window resizing for example).
3305 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
3306 if (!m_scrollbarsSuppressed)
3307 scrollbarExistenceDidChange();
3309 bool hasHorizontalScrollbar = m_horizontalScrollbar;
3310 bool hasVerticalScrollbar = m_verticalScrollbar;
3312 bool newHasHorizontalScrollbar = false;
3313 bool newHasVerticalScrollbar = false;
3314 computeScrollbarExistence(newHasHorizontalScrollbar, newHasVerticalScrollbar, contentsSize(), option);
3316 bool scrollbarExistenceChanged = hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar;
3317 if (!scrollbarExistenceChanged)
3318 return false;
3320 setHasHorizontalScrollbar(newHasHorizontalScrollbar);
3321 setHasVerticalScrollbar(newHasVerticalScrollbar);
3323 if (m_scrollbarsSuppressed)
3324 return true;
3326 if (!hasOverlayScrollbars())
3327 contentsResized();
3328 scrollbarExistenceDidChange();
3329 return true;
3332 bool FrameView::needsScrollbarReconstruction() const
3334 Element* customScrollbarElement = nullptr;
3335 LocalFrame* customScrollbarFrame = nullptr;
3336 bool shouldUseCustom = shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame);
3338 bool hasAnyScrollbar = m_horizontalScrollbar || m_verticalScrollbar;
3339 bool hasCustom = (m_horizontalScrollbar && m_horizontalScrollbar->isCustomScrollbar())
3340 || (m_verticalScrollbar && m_verticalScrollbar->isCustomScrollbar());
3342 return hasAnyScrollbar && (shouldUseCustom != hasCustom);
3345 bool FrameView::shouldIgnoreOverflowHidden() const
3347 return m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame();
3350 void FrameView::updateScrollbars(const DoubleSize& desiredOffset)
3352 // Avoid drawing two sets of scrollbars when visual viewport is enabled.
3353 if (visualViewportSuppliesScrollbars()) {
3354 setHasHorizontalScrollbar(false);
3355 setHasVerticalScrollbar(false);
3356 setScrollOffsetFromUpdateScrollbars(desiredOffset);
3357 return;
3360 if (m_inUpdateScrollbars)
3361 return;
3362 InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
3364 IntSize oldVisibleSize = visibleContentSize();
3366 bool scrollbarExistenceChanged = false;
3368 if (needsScrollbarReconstruction()) {
3369 setHasHorizontalScrollbar(false);
3370 setHasVerticalScrollbar(false);
3371 scrollbarExistenceChanged = true;
3374 int maxUpdateScrollbarsPass = hasOverlayScrollbars() || m_scrollbarsSuppressed ? 1 : 3;
3375 for (int updateScrollbarsPass = 0; updateScrollbarsPass < maxUpdateScrollbarsPass; updateScrollbarsPass++) {
3376 if (!adjustScrollbarExistence(updateScrollbarsPass ? Incremental : FirstPass))
3377 break;
3378 scrollbarExistenceChanged = true;
3381 updateScrollbarGeometry();
3383 if (scrollbarExistenceChanged) {
3384 // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
3385 frameRectsChanged();
3386 positionScrollbarLayers();
3387 updateScrollCorner();
3390 // FIXME: We don't need to do this if we are composited.
3391 IntSize newVisibleSize = visibleContentSize();
3392 if (newVisibleSize.width() > oldVisibleSize.width()) {
3393 if (shouldPlaceVerticalScrollbarOnLeft())
3394 invalidateRect(IntRect(0, 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height()));
3395 else
3396 invalidateRect(IntRect(oldVisibleSize.width(), 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height()));
3398 if (newVisibleSize.height() > oldVisibleSize.height())
3399 invalidateRect(IntRect(0, oldVisibleSize.height(), newVisibleSize.width(), newVisibleSize.height() - oldVisibleSize.height()));
3401 setScrollOffsetFromUpdateScrollbars(desiredOffset);
3404 void FrameView::setScrollOffsetFromUpdateScrollbars(const DoubleSize& offset)
3406 DoublePoint adjustedScrollPosition = clampScrollPosition(DoublePoint(offset));
3408 if (adjustedScrollPosition != scrollPositionDouble() || scrollOriginChanged()) {
3409 ScrollableArea::setScrollPosition(adjustedScrollPosition, ProgrammaticScroll);
3410 resetScrollOriginChanged();
3414 IntRect FrameView::rectToCopyOnScroll() const
3416 IntRect scrollViewRect = convertToContainingWindow(IntRect((shouldPlaceVerticalScrollbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visibleWidth(), visibleHeight()));
3417 if (hasOverlayScrollbars()) {
3418 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
3419 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
3421 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
3422 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
3424 return scrollViewRect;
3427 void FrameView::scrollContentsIfNeeded()
3429 if (m_pendingScrollDelta.isZero())
3430 return;
3431 DoubleSize scrollDelta = m_pendingScrollDelta;
3432 m_pendingScrollDelta = DoubleSize();
3433 // FIXME: Change scrollContents() to take DoubleSize. crbug.com/414283.
3434 scrollContents(flooredIntSize(scrollDelta));
3437 void FrameView::scrollContents(const IntSize& scrollDelta)
3439 HostWindow* window = hostWindow();
3440 if (!window)
3441 return;
3443 TRACE_EVENT0("blink", "FrameView::scrollContents");
3445 IntRect clipRect = windowClipRect();
3446 IntRect updateRect = clipRect;
3447 updateRect.intersect(rectToCopyOnScroll());
3449 if (!scrollContentsFastPath(-scrollDelta))
3450 scrollContentsSlowPath(updateRect);
3452 // This call will move children with native widgets (plugins) and invalidate them as well.
3453 frameRectsChanged();
3456 IntPoint FrameView::contentsToFrame(const IntPoint& pointInContentSpace) const
3458 return pointInContentSpace - scrollOffset();
3461 IntRect FrameView::contentsToFrame(const IntRect& rectInContentSpace) const
3463 return IntRect(contentsToFrame(rectInContentSpace.location()), rectInContentSpace.size());
3466 FloatPoint FrameView::frameToContents(const FloatPoint& pointInFrame) const
3468 return pointInFrame + scrollOffset();
3471 IntPoint FrameView::frameToContents(const IntPoint& pointInFrame) const
3473 return pointInFrame + scrollOffset();
3476 IntRect FrameView::frameToContents(const IntRect& rectInFrame) const
3478 return IntRect(frameToContents(rectInFrame.location()), rectInFrame.size());
3481 IntPoint FrameView::rootFrameToContents(const IntPoint& rootFramePoint) const
3483 IntPoint framePoint = convertFromContainingWindow(rootFramePoint);
3484 return frameToContents(framePoint);
3487 IntRect FrameView::rootFrameToContents(const IntRect& rootFrameRect) const
3489 return IntRect(rootFrameToContents(rootFrameRect.location()), rootFrameRect.size());
3492 IntPoint FrameView::contentsToRootFrame(const IntPoint& contentsPoint) const
3494 IntPoint framePoint = contentsToFrame(contentsPoint);
3495 return convertToContainingWindow(framePoint);
3498 IntRect FrameView::contentsToRootFrame(const IntRect& contentsRect) const
3500 IntRect rectInFrame = contentsToFrame(contentsRect);
3501 return convertToContainingWindow(rectInFrame);
3504 FloatPoint FrameView::rootFrameToContents(const FloatPoint& windowPoint) const
3506 FloatPoint framePoint = convertFromContainingWindow(windowPoint);
3507 return frameToContents(framePoint);
3510 IntRect FrameView::viewportToContents(const IntRect& rectInViewport) const
3512 IntRect rectInRootFrame = m_frame->host()->visualViewport().viewportToRootFrame(rectInViewport);
3513 IntRect frameRect = convertFromContainingWindow(rectInRootFrame);
3514 return frameToContents(frameRect);
3517 IntPoint FrameView::viewportToContents(const IntPoint& pointInViewport) const
3519 IntPoint pointInRootFrame = m_frame->host()->visualViewport().viewportToRootFrame(pointInViewport);
3520 IntPoint pointInFrame = convertFromContainingWindow(pointInRootFrame);
3521 return frameToContents(pointInFrame);
3524 IntRect FrameView::contentsToViewport(const IntRect& rectInContents) const
3526 IntRect rectInFrame = contentsToFrame(rectInContents);
3527 IntRect rectInRootFrame = convertToContainingWindow(rectInFrame);
3528 return m_frame->host()->visualViewport().rootFrameToViewport(rectInRootFrame);
3531 IntPoint FrameView::contentsToViewport(const IntPoint& pointInContents) const
3533 IntPoint pointInFrame = contentsToFrame(pointInContents);
3534 IntPoint pointInRootFrame = convertToContainingWindow(pointInFrame);
3535 return m_frame->host()->visualViewport().rootFrameToViewport(pointInRootFrame);
3538 IntRect FrameView::contentsToScreen(const IntRect& rect) const
3540 HostWindow* window = hostWindow();
3541 if (!window)
3542 return IntRect();
3543 return window->viewportToScreen(contentsToViewport(rect));
3546 IntRect FrameView::soonToBeRemovedContentsToUnscaledViewport(const IntRect& rectInContents) const
3548 IntRect rectInFrame = contentsToFrame(rectInContents);
3549 IntRect rectInRootFrame = convertToContainingWindow(rectInFrame);
3550 return enclosingIntRect(m_frame->host()->visualViewport().mainViewToViewportCSSPixels(rectInRootFrame));
3553 IntPoint FrameView::soonToBeRemovedUnscaledViewportToContents(const IntPoint& pointInViewport) const
3555 IntPoint pointInRootFrame = flooredIntPoint(m_frame->host()->visualViewport().viewportCSSPixelsToRootFrame(pointInViewport));
3556 IntPoint pointInThisFrame = convertFromContainingWindow(pointInRootFrame);
3557 return frameToContents(pointInThisFrame);
3560 bool FrameView::containsScrollbarsAvoidingResizer() const
3562 return !m_scrollbarsAvoidingResizer;
3565 void FrameView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
3567 int oldCount = m_scrollbarsAvoidingResizer;
3568 m_scrollbarsAvoidingResizer += overlapDelta;
3569 if (parent()) {
3570 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(overlapDelta);
3571 } else if (!scrollbarsSuppressed()) {
3572 // If we went from n to 0 or from 0 to n and we're the outermost view,
3573 // we need to invalidate the windowResizerRect(), since it will now need to paint
3574 // differently.
3575 if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0)
3576 || (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
3577 invalidateRect(windowResizerRect());
3581 void FrameView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
3583 if (suppressed == m_scrollbarsSuppressed)
3584 return;
3586 m_scrollbarsSuppressed = suppressed;
3588 if (repaintOnUnsuppress && !suppressed) {
3589 if (m_horizontalScrollbar)
3590 m_horizontalScrollbar->invalidate();
3591 if (m_verticalScrollbar)
3592 m_verticalScrollbar->invalidate();
3594 // Invalidate the scroll corner too on unsuppress.
3595 invalidateScrollCorner(scrollCornerRect());
3599 Scrollbar* FrameView::scrollbarAtRootFramePoint(const IntPoint& pointInRootFrame)
3601 IntPoint pointInFrame = convertFromContainingWindow(pointInRootFrame);
3602 return scrollbarAtFramePoint(pointInFrame);
3605 Scrollbar* FrameView::scrollbarAtFramePoint(const IntPoint& pointInFrame)
3607 if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(pointInFrame))
3608 return m_horizontalScrollbar.get();
3609 if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(pointInFrame))
3610 return m_verticalScrollbar.get();
3611 return nullptr;
3614 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
3616 if (!graphicsLayer || !scrollbar)
3617 return;
3619 IntRect scrollbarRect = scrollbar->frameRect();
3620 graphicsLayer->setPosition(scrollbarRect.location());
3622 if (scrollbarRect.size() == graphicsLayer->size())
3623 return;
3625 graphicsLayer->setSize(scrollbarRect.size());
3627 if (graphicsLayer->hasContentsLayer()) {
3628 graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height()));
3629 return;
3632 graphicsLayer->setDrawsContent(true);
3633 graphicsLayer->setNeedsDisplay();
3636 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
3638 if (!graphicsLayer)
3639 return;
3640 graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
3641 graphicsLayer->setPosition(cornerRect.location());
3642 if (cornerRect.size() != graphicsLayer->size())
3643 graphicsLayer->setNeedsDisplay();
3644 graphicsLayer->setSize(cornerRect.size());
3647 void FrameView::positionScrollbarLayers()
3649 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
3650 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
3651 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
3654 bool FrameView::userInputScrollable(ScrollbarOrientation orientation) const
3656 Document* document = frame().document();
3657 Element* fullscreenElement = Fullscreen::fullscreenElementFrom(*document);
3658 if (fullscreenElement && fullscreenElement != document->documentElement())
3659 return false;
3661 if (frame().settings() && frame().settings()->rootLayerScrolls())
3662 return false;
3664 ScrollbarMode mode = (orientation == HorizontalScrollbar) ?
3665 m_horizontalScrollbarMode : m_verticalScrollbarMode;
3667 return mode == ScrollbarAuto || mode == ScrollbarAlwaysOn;
3670 bool FrameView::shouldPlaceVerticalScrollbarOnLeft() const
3672 return false;
3675 LayoutRect FrameView::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
3677 LayoutRect viewRect(visibleContentRect());
3678 LayoutRect exposeRect = ScrollAlignment::getRectToExpose(viewRect, rectInContent, alignX, alignY);
3680 double xOffset = exposeRect.x();
3681 double yOffset = exposeRect.y();
3683 setScrollPosition(DoublePoint(xOffset, yOffset), ProgrammaticScroll);
3685 // Scrolling the FrameView cannot change the input rect's location relative to the document.
3686 return rectInContent;
3689 IntRect FrameView::scrollCornerRect() const
3691 IntRect cornerRect;
3693 if (hasOverlayScrollbars())
3694 return cornerRect;
3696 if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
3697 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : m_horizontalScrollbar->width(),
3698 height() - m_horizontalScrollbar->height(),
3699 width() - m_horizontalScrollbar->width(),
3700 m_horizontalScrollbar->height()));
3703 if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
3704 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()),
3705 m_verticalScrollbar->height(),
3706 m_verticalScrollbar->width(),
3707 height() - m_verticalScrollbar->height()));
3710 return cornerRect;
3713 bool FrameView::isScrollCornerVisible() const
3715 return !scrollCornerRect().isEmpty();
3718 void FrameView::invalidateScrollCornerRect(const IntRect& rect)
3720 invalidateRect(rect);
3721 if (m_scrollCorner)
3722 layoutView()->invalidateDisplayItemClientForNonCompositingDescendantsOf(*m_scrollCorner);
3725 ScrollBehavior FrameView::scrollBehaviorStyle() const
3727 Element* scrollElement = m_frame->document()->scrollingElement();
3728 LayoutObject* layoutObject = scrollElement ? scrollElement->layoutObject() : nullptr;
3729 if (layoutObject && layoutObject->style()->scrollBehavior() == ScrollBehaviorSmooth)
3730 return ScrollBehaviorSmooth;
3732 return ScrollBehaviorInstant;
3735 void FrameView::paint(GraphicsContext* context, const IntRect& rect)
3737 paint(context, GlobalPaintNormalPhase, rect);
3740 void FrameView::paint(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const IntRect& rect)
3742 FramePainter(*this).paint(context, globalPaintFlags, rect);
3745 void FrameView::paintContents(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const IntRect& damageRect)
3747 FramePainter(*this).paintContents(context, globalPaintFlags, damageRect);
3750 bool FrameView::isPointInScrollbarCorner(const IntPoint& windowPoint)
3752 if (!scrollbarCornerPresent())
3753 return false;
3755 IntPoint framePoint = convertFromContainingWindow(windowPoint);
3757 if (m_horizontalScrollbar) {
3758 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
3759 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
3760 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
3762 return framePoint.y() > horizontalScrollbarYMin && framePoint.y() < horizontalScrollbarYMax && framePoint.x() > horizontalScrollbarXMin;
3765 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
3766 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
3767 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
3769 return framePoint.x() > verticalScrollbarXMin && framePoint.x() < verticalScrollbarXMax && framePoint.y() > verticalScrollbarYMin;
3772 bool FrameView::scrollbarCornerPresent() const
3774 return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0)
3775 || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
3778 IntRect FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
3780 // Scrollbars won't be transformed within us
3781 IntRect newRect = localRect;
3782 newRect.moveBy(scrollbar->location());
3783 return newRect;
3786 IntRect FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
3788 IntRect newRect = parentRect;
3789 // Scrollbars won't be transformed within us
3790 newRect.moveBy(-scrollbar->location());
3791 return newRect;
3794 // FIXME: test these on windows
3795 IntPoint FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
3797 // Scrollbars won't be transformed within us
3798 IntPoint newPoint = localPoint;
3799 newPoint.moveBy(scrollbar->location());
3800 return newPoint;
3803 IntPoint FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
3805 IntPoint newPoint = parentPoint;
3806 // Scrollbars won't be transformed within us
3807 newPoint.moveBy(-scrollbar->location());
3808 return newPoint;
3811 void FrameView::setParentVisible(bool visible)
3813 if (isParentVisible() == visible)
3814 return;
3816 Widget::setParentVisible(visible);
3818 if (!isSelfVisible())
3819 return;
3821 for (const auto& child : m_children)
3822 child->setParentVisible(visible);
3825 void FrameView::show()
3827 if (!isSelfVisible()) {
3828 setSelfVisible(true);
3829 updateScrollableAreaSet();
3830 if (isParentVisible()) {
3831 for (const auto& child : m_children)
3832 child->setParentVisible(true);
3836 Widget::show();
3839 void FrameView::hide()
3841 if (isSelfVisible()) {
3842 if (isParentVisible()) {
3843 for (const auto& child : m_children)
3844 child->setParentVisible(false);
3846 setSelfVisible(false);
3847 updateScrollableAreaSet();
3850 Widget::hide();
3853 void FrameView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
3855 if (scrollOrigin() == origin)
3856 return;
3858 ScrollableArea::setScrollOrigin(origin);
3860 // Update if the scroll origin changes, since our position will be different if the content size did not change.
3861 if (updatePositionAtAll && updatePositionSynchronously)
3862 updateScrollbars(scrollOffsetDouble());
3865 int FrameView::viewportWidth() const
3867 int viewportWidth = layoutSize(IncludeScrollbars).width();
3868 return adjustForAbsoluteZoom(viewportWidth, layoutView());
3871 ScrollableArea* FrameView::scrollableArea()
3873 if (m_viewportScrollableArea)
3874 return m_viewportScrollableArea.get();
3876 return layoutViewportScrollableArea();
3879 ScrollableArea* FrameView::layoutViewportScrollableArea()
3881 Settings* settings = frame().settings();
3882 if (!settings || !settings->rootLayerScrolls())
3883 return this;
3885 LayoutView* layoutView = this->layoutView();
3886 return layoutView ? layoutView->scrollableArea() : nullptr;
3889 LayoutObject* FrameView::viewportLayoutObject()
3891 if (Document* document = frame().document()) {
3892 if (Element* element = document->viewportDefiningElement())
3893 return element->layoutObject();
3895 return nullptr;
3898 void FrameView::collectAnnotatedRegions(LayoutObject& layoutObject, Vector<AnnotatedRegionValue>& regions)
3900 // LayoutTexts don't have their own style, they just use their parent's style,
3901 // so we don't want to include them.
3902 if (layoutObject.isText())
3903 return;
3905 layoutObject.addAnnotatedRegions(regions);
3906 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; curr = curr->nextSibling())
3907 collectAnnotatedRegions(*curr, regions);
3910 void FrameView::collectFrameTimingRequestsRecursive(GraphicsLayerFrameTimingRequests& graphicsLayerTimingRequests)
3912 if (!m_frameTimingRequestsDirty)
3913 return;
3915 collectFrameTimingRequests(graphicsLayerTimingRequests);
3917 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
3918 if (!child->isLocalFrame())
3919 continue;
3921 toLocalFrame(child)->view()->collectFrameTimingRequestsRecursive(graphicsLayerTimingRequests);
3923 m_frameTimingRequestsDirty = false;
3926 void FrameView::collectFrameTimingRequests(GraphicsLayerFrameTimingRequests& graphicsLayerTimingRequests)
3928 if (!m_frame->isLocalFrame())
3929 return;
3930 Frame* frame = m_frame.get();
3931 LocalFrame* localFrame = toLocalFrame(frame);
3932 LayoutRect viewRect = localFrame->contentLayoutObject()->viewRect();
3933 const LayoutBoxModelObject* paintInvalidationContainer = localFrame->contentLayoutObject()->containerForPaintInvalidation();
3934 const GraphicsLayer* graphicsLayer = paintInvalidationContainer->enclosingLayer()->graphicsLayerBacking();
3936 if (!graphicsLayer)
3937 return;
3939 DeprecatedPaintLayer::mapRectToPaintInvalidationBacking(localFrame->contentLayoutObject(), paintInvalidationContainer, viewRect);
3941 graphicsLayerTimingRequests.add(graphicsLayer, Vector<std::pair<int64_t, WebRect>>()).storedValue->value.append(std::make_pair(m_frame->frameID(), enclosingIntRect(viewRect)));
3944 } // namespace blink