2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Dirk Mueller <mueller@kde.org>
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9 * Copyright (C) 2009 Google Inc. All rights reserved.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
28 #include "core/frame/FrameView.h"
30 #include "HTMLNames.h"
31 #include "RuntimeEnabledFeatures.h"
32 #include "core/accessibility/AXObjectCache.h"
33 #include "core/css/FontFaceSet.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/DocumentMarkerController.h"
36 #include "core/editing/FrameSelection.h"
37 #include "core/events/OverflowEvent.h"
38 #include "core/fetch/ResourceFetcher.h"
39 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
40 #include "core/frame/LocalFrame.h"
41 #include "core/frame/Settings.h"
42 #include "core/html/HTMLFrameElement.h"
43 #include "core/html/HTMLPlugInElement.h"
44 #include "core/html/parser/TextResourceDecoder.h"
45 #include "core/inspector/InspectorInstrumentation.h"
46 #include "core/loader/FrameLoader.h"
47 #include "core/loader/FrameLoaderClient.h"
48 #include "core/page/Chrome.h"
49 #include "core/page/ChromeClient.h"
50 #include "core/page/EventHandler.h"
51 #include "core/page/FocusController.h"
52 #include "core/page/FrameTree.h"
53 #include "core/page/scrolling/ScrollingCoordinator.h"
54 #include "core/rendering/FastTextAutosizer.h"
55 #include "core/rendering/RenderCounter.h"
56 #include "core/rendering/RenderEmbeddedObject.h"
57 #include "core/rendering/RenderLayer.h"
58 #include "core/rendering/RenderListBox.h"
59 #include "core/rendering/RenderPart.h"
60 #include "core/rendering/RenderScrollbar.h"
61 #include "core/rendering/RenderScrollbarPart.h"
62 #include "core/rendering/RenderTheme.h"
63 #include "core/rendering/RenderView.h"
64 #include "core/rendering/RenderWidget.h"
65 #include "core/rendering/TextAutosizer.h"
66 #include "core/rendering/compositing/CompositedLayerMapping.h"
67 #include "core/rendering/compositing/RenderLayerCompositor.h"
68 #include "core/rendering/style/RenderStyle.h"
69 #include "core/rendering/svg/RenderSVGRoot.h"
70 #include "core/svg/SVGDocument.h"
71 #include "core/svg/SVGSVGElement.h"
72 #include "platform/TraceEvent.h"
73 #include "platform/fonts/FontCache.h"
74 #include "platform/geometry/FloatRect.h"
75 #include "platform/graphics/GraphicsContext.h"
76 #include "platform/graphics/GraphicsLayerDebugInfo.h"
77 #include "platform/scroll/ScrollAnimator.h"
78 #include "platform/scroll/ScrollbarTheme.h"
79 #include "platform/text/TextStream.h"
80 #include "wtf/CurrentTime.h"
81 #include "wtf/TemporaryChange.h"
85 using namespace HTMLNames;
87 double FrameView::s_currentFrameTimeStamp = 0.0;
88 bool FrameView::s_inPaintContents = false;
90 // The maximum number of updateWidgets iterations that should be done before returning.
91 static const unsigned maxUpdateWidgetsIterations = 2;
92 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
94 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
96 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
99 flags &= ~RenderLayer::CheckForRepaint;
100 flags |= RenderLayer::NeedsFullRepaintInBacking;
102 if (isRelayoutingSubtree && layer->isPaginated())
103 flags |= RenderLayer::UpdatePagination;
107 class FrameViewLayoutStateMaintainer {
108 WTF_MAKE_NONCOPYABLE(FrameViewLayoutStateMaintainer);
110 FrameViewLayoutStateMaintainer(RenderObject& root, bool inSubtreeLayout)
111 : m_view(*root.view())
112 , m_inSubtreeLayout(inSubtreeLayout)
113 , m_disabled(inSubtreeLayout && m_view.shouldDisableLayoutStateForSubtree(root))
115 if (m_inSubtreeLayout)
116 m_view.pushLayoutState(root);
118 m_view.disableLayoutState();
121 ~FrameViewLayoutStateMaintainer()
124 m_view.enableLayoutState();
125 if (m_inSubtreeLayout)
126 m_view.popLayoutState();
130 bool m_inSubtreeLayout;
134 FrameView::FrameView(LocalFrame* frame)
136 , m_canHaveScrollbars(true)
137 , m_slowRepaintObjectCount(0)
138 , m_hasPendingLayout(false)
139 , m_layoutSubtreeRoot(0)
140 , m_inSynchronousPostLayout(false)
141 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
142 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
143 , m_isTransparent(false)
144 , m_baseBackgroundColor(Color::white)
145 , m_mediaType("screen")
146 , m_overflowStatusDirty(true)
147 , m_viewportRenderer(0)
148 , m_wasScrolledByUser(false)
149 , m_inProgrammaticScroll(false)
150 , m_safeToPropagateScrollToParent(true)
151 , m_isTrackingRepaints(false)
153 , m_shouldAutoSize(false)
154 , m_inAutoSize(false)
155 , m_didRunAutosize(false)
156 , m_hasSoftwareFilters(false)
157 , m_visibleContentScaleFactor(1)
158 , m_inputEventsScaleFactorForEmulation(1)
159 , m_layoutSizeFixedToFrameSize(true)
160 , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
168 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
169 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed);
172 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame)
174 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
176 return view.release();
179 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
181 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
182 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
183 view->setLayoutSizeInternal(initialSize);
186 return view.release();
189 FrameView::~FrameView()
191 if (m_postLayoutTasksTimer.isActive())
192 m_postLayoutTasksTimer.stop();
194 if (m_didScrollTimer.isActive())
195 m_didScrollTimer.stop();
197 removeFromAXObjectCache();
200 // Custom scrollbars should already be destroyed at this point
201 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
202 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
204 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
205 setHasVerticalScrollbar(false);
207 ASSERT(!m_scrollCorner);
210 ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
211 RenderPart* renderer = m_frame->ownerRenderer();
212 if (renderer && renderer->widget() == this)
213 renderer->setWidget(nullptr);
216 void FrameView::reset()
218 m_cannotBlitToWindow = false;
219 m_isOverlapped = false;
220 m_contentIsOpaque = false;
221 m_hasPendingLayout = false;
222 m_layoutSubtreeRoot = 0;
223 m_doFullRepaint = false;
224 m_layoutSchedulingEnabled = true;
225 m_inPerformLayout = false;
226 m_canRepaintDuringPerformLayout = false;
227 m_doingPreLayoutStyleUpdate = false;
228 m_inSynchronousPostLayout = false;
230 m_nestedLayoutCount = 0;
231 m_postLayoutTasksTimer.stop();
232 m_updateWidgetsTimer.stop();
233 m_firstLayout = true;
234 m_firstLayoutCallbackPending = false;
235 m_wasScrolledByUser = false;
236 m_safeToPropagateScrollToParent = true;
237 m_lastViewportSize = IntSize();
238 m_lastZoomFactor = 1.0f;
239 m_isTrackingRepaints = false;
240 m_trackedRepaintRects.clear();
242 m_paintBehavior = PaintBehaviorNormal;
243 m_isPainting = false;
244 m_visuallyNonEmptyCharacterCount = 0;
245 m_visuallyNonEmptyPixelCount = 0;
246 m_isVisuallyNonEmpty = false;
247 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
248 m_maintainScrollPositionAnchor = nullptr;
249 m_viewportConstrainedObjects.clear();
252 void FrameView::removeFromAXObjectCache()
254 if (AXObjectCache* cache = axObjectCache())
258 void FrameView::resetScrollbars()
260 // Reset the document's scrollbars back to our defaults before we yield the floor.
261 m_firstLayout = true;
262 setScrollbarsSuppressed(true);
263 if (m_canHaveScrollbars)
264 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
266 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
267 setScrollbarsSuppressed(false);
270 void FrameView::init()
274 m_size = LayoutSize();
276 // Propagate the marginwidth/height and scrolling modes to the view.
277 Element* ownerElement = m_frame->ownerElement();
278 if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) {
279 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
280 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
281 setCanHaveScrollbars(false);
285 void FrameView::prepareForDetach()
287 RELEASE_ASSERT(!isInPerformLayout());
289 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
290 scrollAnimator->cancelAnimations();
292 detachCustomScrollbars();
293 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
294 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
295 removeFromAXObjectCache();
297 if (m_frame->page()) {
298 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
299 scrollingCoordinator->willDestroyScrollableArea(this);
303 void FrameView::detachCustomScrollbars()
305 Scrollbar* horizontalBar = horizontalScrollbar();
306 if (horizontalBar && horizontalBar->isCustomScrollbar())
307 setHasHorizontalScrollbar(false);
309 Scrollbar* verticalBar = verticalScrollbar();
310 if (verticalBar && verticalBar->isCustomScrollbar())
311 setHasVerticalScrollbar(false);
313 if (m_scrollCorner) {
314 m_scrollCorner->destroy();
319 void FrameView::recalculateScrollbarOverlayStyle()
321 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
322 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
324 Color backgroundColor = documentBackgroundColor();
325 // Reduce the background color from RGB to a lightness value
326 // and determine which scrollbar style to use based on a lightness
328 double hue, saturation, lightness;
329 backgroundColor.getHSL(hue, saturation, lightness);
331 overlayStyle = ScrollbarOverlayStyleLight;
333 if (oldOverlayStyle != overlayStyle)
334 setScrollbarOverlayStyle(overlayStyle);
337 void FrameView::clear()
340 setScrollbarsSuppressed(true);
343 bool FrameView::didFirstLayout() const
345 return !m_firstLayout;
348 void FrameView::invalidateRect(const IntRect& rect)
351 if (HostWindow* window = hostWindow())
352 window->invalidateContentsAndRootView(rect);
356 RenderPart* renderer = m_frame->ownerRenderer();
360 IntRect repaintRect = rect;
361 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
362 renderer->borderTop() + renderer->paddingTop());
363 renderer->repaintRectangle(repaintRect);
366 void FrameView::setFrameRect(const IntRect& newRect)
368 IntRect oldRect = frameRect();
369 if (newRect == oldRect)
372 // Autosized font sizes depend on the width of the viewing area.
373 if (newRect.width() != oldRect.width()) {
374 if (isMainFrame() && m_frame->settings()->textAutosizingEnabled()) {
375 for (LocalFrame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext()) {
376 if (TextAutosizer* textAutosizer = frame->document()->textAutosizer())
377 textAutosizer->recalculateMultipliers();
382 ScrollView::setFrameRect(newRect);
384 updateScrollableAreaSet();
386 if (RenderView* renderView = this->renderView()) {
387 if (renderView->usesCompositing())
388 renderView->compositor()->frameViewDidChangeSize();
391 viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
394 bool FrameView::scheduleAnimation()
396 if (HostWindow* window = hostWindow()) {
397 window->scheduleAnimation();
403 Page* FrameView::page() const
405 return frame().page();
408 RenderView* FrameView::renderView() const
410 return frame().contentRenderer();
413 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
415 m_canHaveScrollbars = canHaveScrollbars;
416 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
419 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame)
421 customScrollbarElement = 0;
422 customScrollbarFrame = 0;
424 if (Settings* settings = m_frame->settings()) {
425 if (!settings->allowCustomScrollbarInMainFrame() && isMainFrame())
429 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
430 Document* doc = m_frame->document();
432 // Try the <body> element first as a scrollbar source.
433 Element* body = doc ? doc->body() : 0;
434 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
435 customScrollbarElement = body;
439 // If the <body> didn't have a custom style, then the root element might.
440 Element* docElement = doc ? doc->documentElement() : 0;
441 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
442 customScrollbarElement = docElement;
446 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
447 RenderPart* frameRenderer = m_frame->ownerRenderer();
448 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) {
449 customScrollbarFrame = m_frame.get();
456 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
458 Element* customScrollbarElement = 0;
459 LocalFrame* customScrollbarFrame = 0;
460 if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
461 return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
463 // Nobody set a custom style, so we just use a native scrollbar.
464 return ScrollView::createScrollbar(orientation);
467 void FrameView::setContentsSize(const IntSize& size)
469 if (size == contentsSize())
472 ScrollView::setContentsSize(size);
473 ScrollView::contentsResized();
475 Page* page = frame().page();
479 updateScrollableAreaSet();
481 page->chrome().contentsSizeChanged(m_frame.get(), size);
484 IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const
486 IntPoint maxScrollExtent(contentsSize().width() - scrollOrigin().x(), contentsSize().height() - scrollOrigin().y());
487 FloatSize scaledSize = unscaledVisibleContentSize();
489 scaledSize.scale(1 / scale);
491 IntPoint clampedOffset = offset;
492 clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize));
493 clampedOffset = clampedOffset.expandedTo(-scrollOrigin());
495 return clampedOffset;
498 void FrameView::adjustViewSize()
500 RenderView* renderView = this->renderView();
504 ASSERT(m_frame->view() == this);
506 const IntRect rect = renderView->documentRect();
507 const IntSize& size = rect.size();
508 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
510 setContentsSize(size);
513 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
515 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
516 // overflow:hidden and overflow:scroll on <body> as applying to the document's
517 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
518 // use the root element.
520 EOverflow overflowX = o->style()->overflowX();
521 EOverflow overflowY = o->style()->overflowY();
523 if (o->isSVGRoot()) {
524 // overflow is ignored in stand-alone SVG documents.
525 if (!toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument())
531 bool ignoreOverflowHidden = false;
532 if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame())
533 ignoreOverflowHidden = true;
537 if (!ignoreOverflowHidden)
538 hMode = ScrollbarAlwaysOff;
541 hMode = ScrollbarAlwaysOn;
544 hMode = ScrollbarAuto;
547 // Don't set it at all.
553 if (!ignoreOverflowHidden)
554 vMode = ScrollbarAlwaysOff;
557 vMode = ScrollbarAlwaysOn;
560 vMode = ScrollbarAuto;
563 // Don't set it at all.
567 m_viewportRenderer = o;
570 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
572 m_viewportRenderer = 0;
574 const HTMLFrameOwnerElement* owner = m_frame->ownerElement();
575 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
576 hMode = ScrollbarAlwaysOff;
577 vMode = ScrollbarAlwaysOff;
581 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
582 hMode = ScrollbarAuto;
583 vMode = ScrollbarAuto;
585 hMode = ScrollbarAlwaysOff;
586 vMode = ScrollbarAlwaysOff;
589 if (!isSubtreeLayout()) {
590 Document* document = m_frame->document();
591 Node* body = document->body();
592 if (isHTMLFrameSetElement(body) && body->renderer()) {
593 vMode = ScrollbarAlwaysOff;
594 hMode = ScrollbarAlwaysOff;
595 } else if (Element* viewportElement = document->viewportDefiningElement()) {
596 if (RenderObject* viewportRenderer = viewportElement->renderer()) {
597 if (viewportRenderer->style())
598 applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode);
604 void FrameView::updateCompositingLayersAfterStyleChange()
606 TRACE_EVENT0("webkit", "FrameView::updateCompositingLayersAfterStyleChange");
607 RenderView* renderView = this->renderView();
611 // If we expect to update compositing after an incipient layout, don't do so here.
612 if (m_doingPreLayoutStyleUpdate || layoutPending() || renderView->needsLayout())
615 // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues
616 // https://code.google.com/p/chromium/issues/detail?id=343756
617 DisableCompositingQueryAsserts disabler;
619 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
620 renderView->compositor()->cacheAcceleratedCompositingFlags();
622 // Sometimes we will change a property (for example, z-index) that will not
623 // cause a layout, but will require us to update compositing state. We only
624 // need to do this if a layout is not already scheduled.
626 renderView->compositor()->updateCompositingRequirementsState();
628 renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterStyleChange);
631 void FrameView::updateCompositingLayersAfterLayout()
633 TRACE_EVENT0("webkit", "FrameView::updateCompositingLayersAfterLayout");
634 RenderView* renderView = this->renderView();
638 // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues
639 // https://code.google.com/p/chromium/issues/detail?id=343756
640 DisableCompositingQueryAsserts disabler;
642 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
643 renderView->compositor()->cacheAcceleratedCompositingFlags();
644 renderView->compositor()->updateCompositingRequirementsState();
645 renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterLayout);
648 bool FrameView::usesCompositedScrolling() const
650 RenderView* renderView = this->renderView();
653 if (m_frame->settings() && m_frame->settings()->compositedScrollingForFramesEnabled())
654 return renderView->compositor()->inForcedCompositingMode();
658 GraphicsLayer* FrameView::layerForScrolling() const
660 RenderView* renderView = this->renderView();
663 return renderView->compositor()->scrollLayer();
666 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
668 RenderView* renderView = this->renderView();
671 return renderView->compositor()->layerForHorizontalScrollbar();
674 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
676 RenderView* renderView = this->renderView();
679 return renderView->compositor()->layerForVerticalScrollbar();
682 GraphicsLayer* FrameView::layerForScrollCorner() const
684 RenderView* renderView = this->renderView();
687 return renderView->compositor()->layerForScrollCorner();
690 bool FrameView::hasCompositedContent() const
692 if (RenderView* renderView = this->renderView())
693 return renderView->compositor()->inCompositingMode();
697 bool FrameView::isEnclosedInCompositingLayer() const
699 RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
700 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
703 if (FrameView* parentView = parentFrameView())
704 return parentView->isEnclosedInCompositingLayer();
709 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
711 return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
714 inline void FrameView::forceLayoutParentViewIfNeeded()
716 RenderPart* ownerRenderer = m_frame->ownerRenderer();
717 if (!ownerRenderer || !ownerRenderer->frame())
720 RenderBox* contentBox = embeddedContentBox();
724 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
725 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
728 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
729 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
730 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
731 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
732 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
733 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
734 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
735 RefPtr<FrameView> frameView = ownerRenderer->frame()->view();
737 // Mark the owner renderer as needing layout.
738 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
740 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
745 void FrameView::performPreLayoutTasks()
747 TRACE_EVENT0("webkit", "FrameView::performPreLayoutTasks");
748 lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
750 // Don't schedule more layouts, we're in one.
751 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
753 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
754 // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
755 m_inSynchronousPostLayout = true;
756 performPostLayoutTasks();
757 m_inSynchronousPostLayout = false;
760 Document* document = m_frame->document();
761 document->notifyResizeForViewportUnits();
763 // Viewport-dependent media queries may cause us to need completely different style information.
764 if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) {
765 document->styleResolverChanged(RecalcStyleDeferred);
766 document->mediaQueryAffectingValueChanged();
768 // FIXME: This instrumentation event is not strictly accurate since cached media query results
769 // do not persist across StyleResolver rebuilds.
770 InspectorInstrumentation::mediaQueryResultChanged(document);
772 document->evaluateMediaQueryList();
775 // Always ensure our style info is up-to-date. This can happen in situations where
776 // the layout beats any sort of style recalc update that needs to occur.
777 TemporaryChange<bool> changeDoingPreLayoutStyleUpdate(m_doingPreLayoutStyleUpdate, true);
778 document->updateRenderTreeIfNeeded();
779 lifecycle().advanceTo(DocumentLifecycle::StyleClean);
782 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
784 TRACE_EVENT0("webkit", "FrameView::performLayout");
786 ASSERT(!isInPerformLayout());
787 lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
789 TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
791 // performLayout is the actual guts of layout().
792 // FIXME: The 300 other lines in layout() probably belong in other helper functions
793 // so that a single human could understand what layout() is actually doing.
795 FrameViewLayoutStateMaintainer statePusher(*rootForThisLayout, inSubtreeLayout);
796 forceLayoutParentViewIfNeeded();
798 // FIXME (crbug.com/256657): Do not do two layouts for text autosizing.
799 rootForThisLayout->layout();
800 gatherDebugLayoutRects(rootForThisLayout);
802 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
804 TextAutosizer* textAutosizer = frame().document()->textAutosizer();
805 bool autosized = textAutosizer && textAutosizer->processSubtree(rootForThisLayout);
806 if (autosized && rootForThisLayout->needsLayout()) {
807 TRACE_EVENT0("webkit", "2nd layout due to Text Autosizing");
808 UseCounter::count(*frame().document(), UseCounter::TextAutosizingLayout);
809 rootForThisLayout->layout();
810 gatherDebugLayoutRects(rootForThisLayout);
813 lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
816 void FrameView::scheduleOrPerformPostLayoutTasks()
818 if (m_postLayoutTasksTimer.isActive())
821 if (!m_inSynchronousPostLayout) {
822 m_inSynchronousPostLayout = true;
823 // Calls resumeScheduledEvents()
824 performPostLayoutTasks();
825 m_inSynchronousPostLayout = false;
828 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
829 // If we need layout or are already in a synchronous call to postLayoutTasks(),
830 // defer widget updates and event dispatch until after we return. postLayoutTasks()
831 // can make us need to update again, and we can get stuck in a nasty cycle unless
832 // we call it through the timer here.
833 m_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
839 void FrameView::layout(bool allowSubtree)
841 // We should never layout a Document which is not in a LocalFrame.
843 ASSERT(m_frame->view() == this);
844 ASSERT(m_frame->page());
846 if (isInPerformLayout() || !m_frame->document()->isActive())
849 TRACE_EVENT0("webkit", "FrameView::layout");
850 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "Layout");
852 // Protect the view from being deleted during layout (in recalcStyle)
853 RefPtr<FrameView> protector(this);
855 // Every scroll that happens during layout is programmatic.
856 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
858 m_hasPendingLayout = false;
859 DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
861 RELEASE_ASSERT(!isPainting());
863 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
865 if (!allowSubtree && isSubtreeLayout()) {
866 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
867 m_layoutSubtreeRoot = 0;
870 performPreLayoutTasks();
872 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
873 // so there's no point to continuing to layout
874 if (protector->hasOneRef())
877 Document* document = m_frame->document();
878 bool inSubtreeLayout = isSubtreeLayout();
879 RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderer();
880 if (!rootForThisLayout) {
881 // FIXME: Do we need to set m_size here?
882 ASSERT_NOT_REACHED();
886 bool shouldDoFullLayout = false;
887 FontCachePurgePreventer fontCachePurgePreventer;
890 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
892 m_nestedLayoutCount++;
893 if (!inSubtreeLayout) {
894 Document* document = m_frame->document();
895 Node* body = document->body();
896 if (body && body->renderer()) {
897 if (isHTMLFrameSetElement(*body)) {
898 body->renderer()->setChildNeedsLayout();
899 } else if (isHTMLBodyElement(*body)) {
900 if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport())
901 body->renderer()->setChildNeedsLayout();
910 calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode);
912 shouldDoFullLayout = !inSubtreeLayout && (m_firstLayout || toRenderView(rootForThisLayout)->document().printing());
914 if (!inSubtreeLayout) {
915 // Now set our scrollbar state for the layout.
916 ScrollbarMode currentHMode = horizontalScrollbarMode();
917 ScrollbarMode currentVMode = verticalScrollbarMode();
920 setScrollbarsSuppressed(true);
922 m_firstLayout = false;
923 m_firstLayoutCallbackPending = true;
924 m_lastViewportSize = layoutSize(IncludeScrollbars);
925 m_lastZoomFactor = rootForThisLayout->style()->zoom();
927 // Set the initial vMode to AlwaysOn if we're auto.
928 if (vMode == ScrollbarAuto)
929 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
930 // Set the initial hMode to AlwaysOff if we're auto.
931 if (hMode == ScrollbarAuto)
932 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
934 setScrollbarModes(hMode, vMode);
935 setScrollbarsSuppressed(false, true);
936 } else if (hMode != currentHMode || vMode != currentVMode) {
937 setScrollbarModes(hMode, vMode);
940 LayoutSize oldSize = m_size;
942 m_size = LayoutSize(layoutSize().width(), layoutSize().height());
944 if (oldSize != m_size) {
945 shouldDoFullLayout = true;
946 if (!m_firstLayout) {
947 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
948 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
949 if (bodyRenderer && bodyRenderer->stretchesToViewport())
950 bodyRenderer->setChildNeedsLayout();
951 else if (rootRenderer && rootRenderer->stretchesToViewport())
952 rootRenderer->setChildNeedsLayout();
957 layer = rootForThisLayout->enclosingLayer();
959 // We need to set m_doFullRepaint before triggering layout as RenderObject::checkForRepaint
960 // checks the boolean to disable local repaints.
961 m_doFullRepaint |= shouldDoFullLayout;
963 performLayout(rootForThisLayout, inSubtreeLayout);
965 m_layoutSubtreeRoot = 0;
966 } // Reset m_layoutSchedulingEnabled to its previous value.
968 if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing())
971 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, inSubtreeLayout, m_doFullRepaint));
973 updateCompositingLayersAfterLayout();
977 if (AXObjectCache* cache = rootForThisLayout->document().existingAXObjectCache())
978 cache->postNotification(rootForThisLayout, AXObjectCache::AXLayoutComplete, true);
979 updateAnnotatedRegions();
981 ASSERT(!rootForThisLayout->needsLayout());
983 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
984 updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
986 scheduleOrPerformPostLayoutTasks();
988 InspectorInstrumentation::didLayout(cookie, rootForThisLayout);
990 m_nestedLayoutCount--;
991 if (m_nestedLayoutCount)
994 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
996 renderView()->setShouldDoFullRepaintAfterLayout(true);
998 repaintTree(rootForThisLayout);
1000 } else if (m_doFullRepaint) {
1001 // FIXME: This isn't really right, since the RenderView doesn't fully encompass
1002 // the visibleContentRect(). It just happens to work out most of the time,
1003 // since first layouts and printing don't have you scrolled anywhere.
1004 renderView()->repaint();
1007 m_doFullRepaint = false;
1010 // Post-layout assert that nobody was re-marked as needing layout during layout.
1011 document->renderer()->assertSubtreeIsLaidOut();
1014 // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
1015 // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
1016 // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from
1017 // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
1018 // necessitating this check here.
1019 // ASSERT(frame()->page());
1021 frame().page()->chrome().client().layoutUpdated(m_frame.get());
1024 // The plan is to move to compositor-queried repainting, in which case this
1025 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
1026 // let the compositor pick which to actually draw.
1027 // See http://crbug.com/306706
1028 void FrameView::repaintTree(RenderObject* root)
1030 ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled());
1031 ASSERT(!root->needsLayout());
1032 // We should only repaint for the outer most layout. This works as
1033 // we continue to track repaint rects until this function is called.
1034 ASSERT(!m_nestedLayoutCount);
1036 // FIXME: really, we're in the repaint phase here, and the compositing queries are legal.
1037 // Until those states are fully fledged, I'll just disable the ASSERTS.
1038 DisableCompositingQueryAsserts disabler;
1040 for (RenderObject* renderer = root; renderer; renderer = renderer->nextInPreOrder()) {
1041 const LayoutRect& oldRepaintRect = renderer->oldRepaintRect();
1042 const LayoutRect& newRepaintRect = renderer->newRepaintRect();
1044 if ((renderer->onlyNeededPositionedMovementLayout() && renderer->compositingState() != PaintsIntoOwnBacking)
1045 || (renderer->shouldDoFullRepaintIfSelfPaintingLayer()
1046 && renderer->hasLayer()
1047 && toRenderLayerModelObject(renderer)->layer()->isSelfPaintingLayer())) {
1048 renderer->setShouldDoFullRepaintAfterLayout(true);
1051 // FIXME: Currently renderers with layers will get repainted when we call updateLayerPositionsAfterLayout.
1052 // That call should be broken apart to position the layers be done before
1053 // the repaintTree call so this will repaint everything.
1054 bool didFullRepaint = false;
1055 if (!renderer->layoutDidGetCalled()) {
1056 if (renderer->shouldDoFullRepaintAfterLayout()) {
1057 renderer->repaint();
1058 didFullRepaint = true;
1062 didFullRepaint = renderer->repaintAfterLayoutIfNeeded(renderer->containerForRepaint(),
1063 renderer->shouldDoFullRepaintAfterLayout(), oldRepaintRect, &newRepaintRect);
1066 if (!didFullRepaint)
1067 renderer->repaintOverflowIfNeeded();
1069 // Repaint any scrollbars if there is a scrollable area for this renderer.
1070 if (RenderLayerScrollableArea* area = renderer->enclosingLayer()->scrollableArea()) {
1071 if (area->hasVerticalBarDamage())
1072 renderer->repaintRectangle(area->verticalBarDamage());
1073 if (area->hasHorizontalBarDamage())
1074 renderer->repaintRectangle(area->horizontalBarDamage());
1075 area->resetScrollbarDamage();
1078 // The list box has a verticalScrollbar we may need to repaint.
1079 if (renderer->isListBox()) {
1080 RenderListBox* listBox = static_cast<RenderListBox*>(renderer);
1081 listBox->repaintScrollbarIfNeeded();
1084 renderer->clearRepaintState();
1087 // Repaint the frameviews scrollbars if needed
1088 if (hasVerticalBarDamage())
1089 invalidateRect(verticalBarDamage());
1090 if (hasHorizontalBarDamage())
1091 invalidateRect(horizontalBarDamage());
1092 resetScrollbarDamage();
1095 DocumentLifecycle& FrameView::lifecycle() const
1097 return m_frame->document()->lifecycle();
1100 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot)
1103 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
1106 if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
1108 GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
1112 GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
1114 debugInfo.currentLayoutRects().clear();
1115 for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
1116 if (renderer->layoutDidGetCalled()) {
1117 FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->newRepaintRect()));
1118 LayoutRect rect = quad.enclosingBoundingBox();
1119 debugInfo.currentLayoutRects().append(rect);
1120 renderer->setLayoutDidGetCalled(false);
1125 RenderBox* FrameView::embeddedContentBox() const
1127 RenderView* renderView = this->renderView();
1131 RenderObject* firstChild = renderView->firstChild();
1132 if (!firstChild || !firstChild->isBox())
1135 // Curently only embedded SVG documents participate in the size-negotiation logic.
1136 if (firstChild->isSVGRoot())
1137 return toRenderBox(firstChild);
1143 void FrameView::addWidget(RenderWidget* object)
1145 m_widgets.add(object);
1148 void FrameView::removeWidget(RenderWidget* object)
1150 m_widgets.remove(object);
1153 void FrameView::updateWidgetPositions()
1155 Vector<RefPtr<RenderWidget> > widgets;
1156 copyToVector(m_widgets, widgets);
1158 // Script or plugins could detach the frame so abort processing if that happens.
1160 for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1161 widgets[i]->updateWidgetPosition();
1163 for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1164 widgets[i]->widgetPositionsUpdated();
1167 void FrameView::addWidgetToUpdate(RenderEmbeddedObject& object)
1169 ASSERT(isInPerformLayout());
1170 // Tell the DOM element that it needs a widget update.
1171 Node* node = object.node();
1173 if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node))
1174 toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1176 m_widgetUpdateSet.add(&object);
1179 void FrameView::setMediaType(const AtomicString& mediaType)
1181 ASSERT(m_frame->document());
1182 m_frame->document()->mediaQueryAffectingValueChanged();
1183 m_mediaType = mediaType;
1186 AtomicString FrameView::mediaType() const
1188 // See if we have an override type.
1189 String overrideType;
1190 InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType);
1191 if (!overrideType.isNull())
1192 return AtomicString(overrideType);
1196 void FrameView::adjustMediaTypeForPrinting(bool printing)
1199 if (m_mediaTypeWhenNotPrinting.isNull())
1200 m_mediaTypeWhenNotPrinting = mediaType();
1201 setMediaType("print");
1203 if (!m_mediaTypeWhenNotPrinting.isNull())
1204 setMediaType(m_mediaTypeWhenNotPrinting);
1205 m_mediaTypeWhenNotPrinting = nullAtom;
1209 bool FrameView::useSlowRepaints(bool considerOverlap) const
1211 if (m_slowRepaintObjectCount > 0)
1214 if (contentsInCompositedLayer())
1217 // The chromium compositor does not support scrolling a non-composited frame within a composited page through
1218 // the fast scrolling path, so force slow scrolling in that case.
1219 if (m_frame->ownerElement() && !hasCompositedContent() && m_frame->page() && m_frame->page()->mainFrame()->view()->hasCompositedContent())
1222 if (m_isOverlapped && considerOverlap)
1225 if (m_cannotBlitToWindow)
1228 if (!m_contentIsOpaque)
1231 if (FrameView* parentView = parentFrameView())
1232 return parentView->useSlowRepaints(considerOverlap);
1237 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1239 return useSlowRepaints(false);
1242 bool FrameView::shouldAttemptToScrollUsingFastPath() const
1244 return !useSlowRepaints();
1247 bool FrameView::contentsInCompositedLayer() const
1249 RenderView* renderView = this->renderView();
1250 if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) {
1251 GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer();
1252 if (layer && layer->drawsContent())
1259 void FrameView::setCannotBlitToWindow()
1261 m_cannotBlitToWindow = true;
1264 void FrameView::addSlowRepaintObject()
1266 if (!m_slowRepaintObjectCount++) {
1267 if (Page* page = m_frame->page()) {
1268 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1269 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1274 void FrameView::removeSlowRepaintObject()
1276 ASSERT(m_slowRepaintObjectCount > 0);
1277 m_slowRepaintObjectCount--;
1278 if (!m_slowRepaintObjectCount) {
1279 if (Page* page = m_frame->page()) {
1280 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1281 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1286 void FrameView::addViewportConstrainedObject(RenderObject* object)
1288 if (!m_viewportConstrainedObjects)
1289 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1291 if (!m_viewportConstrainedObjects->contains(object)) {
1292 m_viewportConstrainedObjects->add(object);
1294 if (Page* page = m_frame->page()) {
1295 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1296 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1301 void FrameView::removeViewportConstrainedObject(RenderObject* object)
1303 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1304 m_viewportConstrainedObjects->remove(object);
1306 if (Page* page = m_frame->page()) {
1307 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1308 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1313 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1315 LayoutRect viewportRect = visibleContentRect();
1316 // Ignore overhang. No-op when not using rubber banding.
1317 viewportRect.setLocation(clampScrollPosition(scrollPosition()));
1318 return viewportRect;
1321 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged)
1323 // If viewport is not enabled, frameRect change will cause layout size change and then layout.
1324 // Otherwise, viewport constrained objects need their layout flags set separately to ensure
1325 // they are positioned correctly.
1326 if ((m_frame->settings() && !m_frame->settings()->viewportEnabled()) || !hasViewportConstrainedObjects())
1329 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1330 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1331 RenderObject* renderer = *it;
1332 RenderStyle* style = renderer->style();
1334 if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto()))
1335 renderer->setNeedsPositionedMovementLayout();
1337 renderer->setNeedsLayout();
1339 if (heightChanged) {
1340 if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto()))
1341 renderer->setNeedsPositionedMovementLayout();
1343 renderer->setNeedsLayout();
1348 bool FrameView::shouldPlaceVerticalScrollbarOnLeft() const
1350 // FIXME: Mainframe scrollbar placement should respect the embedding application RTL UI policy.
1351 // See crbug.com/249860.
1355 Document* document = m_frame->document();
1359 // <body> inherits 'direction' from <html>, so it can safaly be used
1360 // to dictate the frame vertical scrollbar placement.
1361 if (!document->body() || !document->body()->renderer())
1364 return document->body()->renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft();
1367 IntSize FrameView::scrollOffsetForFixedPosition() const
1369 return toIntSize(clampScrollPosition(scrollPosition()));
1372 IntPoint FrameView::lastKnownMousePosition() const
1374 return m_frame->eventHandler().lastKnownMousePosition();
1377 bool FrameView::shouldSetCursor() const
1379 Page* page = frame().page();
1380 return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive();
1383 void FrameView::scrollContentsIfNeededRecursive()
1385 scrollContentsIfNeeded();
1387 for (LocalFrame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1388 if (FrameView* view = child->view())
1389 view->scrollContentsIfNeededRecursive();
1393 void FrameView::scrollContentsIfNeeded()
1395 bool didScroll = !pendingScrollDelta().isZero();
1396 ScrollView::scrollContentsIfNeeded();
1398 updateFixedElementRepaintRectsAfterScroll();
1401 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1403 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1404 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1408 const bool isCompositedContentLayer = contentsInCompositedLayer();
1410 // Get the rects of the fixed objects visible in the rectToScroll
1411 Region regionToUpdate;
1412 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1413 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1414 RenderObject* renderer = *it;
1415 // m_viewportConstrainedObjects should not contain non-viewport constrained objects.
1416 ASSERT(renderer->style()->hasViewportConstrainedPosition());
1418 // Fixed items should always have layers.
1419 ASSERT(renderer->hasLayer());
1420 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1422 // Layers that paint into their ancestor or into a grouped backing will still need
1423 // to apply a repaint invalidation. If the layer paints into its own backing, then
1424 // it does not need repainting just to scroll.
1425 if (layer->compositingState() == PaintsIntoOwnBacking)
1428 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1429 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1430 // Don't invalidate for invisible fixed layers.
1434 if (layer->hasAncestorWithFilterOutsets()) {
1435 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1436 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1440 IntRect updateRect = pixelSnappedIntRect(layer->repainter().repaintRectIncludingNonCompositingDescendants());
1442 RenderLayer* enclosingCompositingLayer = layer->enclosingCompositingLayer(ExcludeSelf);
1443 if (enclosingCompositingLayer && !enclosingCompositingLayer->renderer()->isRenderView()) {
1444 // If the fixed-position layer is contained by a composited layer that is not its containing block,
1445 // then we have to invlidate that enclosing layer, not the RenderView.
1446 updateRect.moveBy(scrollPosition());
1447 IntRect previousRect = updateRect;
1448 previousRect.move(scrollDelta);
1449 updateRect.unite(previousRect);
1450 enclosingCompositingLayer->repainter().setBackingNeedsRepaintInRect(updateRect);
1452 // Coalesce the repaints that will be issued to the renderView.
1453 updateRect = contentsToRootView(updateRect);
1454 if (!isCompositedContentLayer && clipsRepaints())
1455 updateRect.intersect(rectToScroll);
1456 if (!updateRect.isEmpty())
1457 regionToUpdate.unite(updateRect);
1462 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1464 // 2) update the area of fixed objects that has been invalidated
1465 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1466 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1467 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1468 IntRect updateRect = subRectsToUpdate[i];
1469 IntRect scrolledRect = updateRect;
1470 scrolledRect.move(-scrollDelta);
1471 updateRect.unite(scrolledRect);
1472 if (isCompositedContentLayer) {
1473 updateRect = rootViewToContents(updateRect);
1474 ASSERT(renderView());
1475 renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect);
1478 if (clipsRepaints())
1479 updateRect.intersect(rectToScroll);
1480 hostWindow()->invalidateContentsAndRootView(updateRect);
1486 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1488 if (contentsInCompositedLayer()) {
1489 IntRect updateRect = visibleContentRect();
1490 ASSERT(renderView());
1491 renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect);
1493 if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
1494 if (isEnclosedInCompositingLayer()) {
1495 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1496 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1497 visibleWidth(), visibleHeight());
1498 frameRenderer->repaintRectangle(rect);
1503 ScrollView::scrollContentsSlowPath(updateRect);
1506 // Note that this gets called at painting time.
1507 void FrameView::setIsOverlapped(bool isOverlapped)
1509 m_isOverlapped = isOverlapped;
1512 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1514 m_contentIsOpaque = contentIsOpaque;
1517 void FrameView::restoreScrollbar()
1519 setScrollbarsSuppressed(false);
1522 bool FrameView::scrollToFragment(const KURL& url)
1524 // If our URL has no ref, then we have no place we need to jump to.
1525 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1526 // and possibly repaint because :target pseudo class may have been
1527 // set (see bug 11321).
1528 if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1531 String fragmentIdentifier = url.fragmentIdentifier();
1532 if (scrollToAnchor(fragmentIdentifier))
1535 // Try again after decoding the ref, based on the document's encoding.
1536 if (m_frame->document()->encoding().isValid())
1537 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()));
1542 bool FrameView::scrollToAnchor(const String& name)
1544 ASSERT(m_frame->document());
1546 if (!m_frame->document()->haveStylesheetsLoaded()) {
1547 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1551 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1553 Element* anchorNode = m_frame->document()->findAnchor(name);
1555 // Setting to null will clear the current target.
1556 m_frame->document()->setCSSTarget(anchorNode);
1558 if (m_frame->document()->isSVGDocument()) {
1559 if (SVGSVGElement* svg = toSVGDocument(m_frame->document())->rootElement()) {
1560 svg->setupInitialView(name, anchorNode);
1566 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1567 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1570 maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1572 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1573 if (anchorNode && anchorNode->isFocusable())
1574 m_frame->document()->setFocusedElement(anchorNode);
1579 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1581 m_maintainScrollPositionAnchor = anchorNode;
1582 if (!m_maintainScrollPositionAnchor)
1585 // We need to update the layout before scrolling, otherwise we could
1586 // really mess things up if an anchor scroll comes at a bad moment.
1587 m_frame->document()->updateRenderTreeIfNeeded();
1588 // Only do a layout if changes have occurred that make it necessary.
1589 RenderView* renderView = this->renderView();
1590 if (renderView && renderView->needsLayout())
1596 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1598 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1600 LayoutRect bounds = element->boundingBox();
1601 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
1602 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
1603 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
1606 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1608 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1609 m_maintainScrollPositionAnchor = nullptr;
1611 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1613 if (newScrollPosition == scrollPosition())
1616 ScrollView::setScrollPosition(newScrollPosition);
1619 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint)
1621 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1623 if (newScrollPosition == scrollPosition())
1626 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false);
1627 notifyScrollPositionChanged(newScrollPosition);
1630 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1632 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1635 void FrameView::setLayoutSize(const IntSize& size)
1637 ASSERT(!layoutSizeFixedToFrameSize());
1639 setLayoutSizeInternal(size);
1642 void FrameView::scrollPositionChanged()
1644 setWasScrolledByUser(true);
1646 Document* document = m_frame->document();
1647 document->enqueueScrollEventForNode(document);
1649 m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1651 if (RenderView* renderView = document->renderView()) {
1652 if (renderView->usesCompositing()) {
1653 // https://code.google.com/p/chromium/issues/detail?id=343767
1654 DisableCompositingQueryAsserts disabler;
1655 renderView->compositor()->frameViewDidScroll();
1659 if (m_didScrollTimer.isActive())
1660 m_didScrollTimer.stop();
1661 m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE);
1663 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1664 cache->handleScrollPositionChanged(this);
1666 frame().loader().saveScrollState();
1669 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1671 if (m_frame->document() && m_frame->document()->renderer()) {
1672 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1676 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
1678 // Nothing to do after scrolling if there are no fixed position elements.
1679 if (!hasViewportConstrainedObjects())
1682 RefPtr<FrameView> protect(this);
1684 // If there fixed position elements, scrolling may cause compositing layers to change.
1685 // Update widget and layer positions after scrolling, but only if we're not inside of
1687 if (!m_nestedLayoutCount) {
1688 updateWidgetPositions();
1689 if (RenderView* renderView = this->renderView())
1690 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
1693 // Compositing layers may change after scrolling.
1694 // FIXME: Maybe no longer needed after we land squashing and kill overlap testing?
1695 if (RenderView* renderView = this->renderView())
1696 renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateOnScroll);
1699 void FrameView::updateFixedElementRepaintRectsAfterScroll()
1701 if (!hasViewportConstrainedObjects())
1704 // Update the repaint rects for fixed elements after scrolling and invalidation to reflect
1705 // the new scroll position.
1706 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1707 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1708 RenderObject* renderer = *it;
1709 // m_viewportConstrainedObjects should not contain non-viewport constrained objects.
1710 ASSERT(renderer->style()->hasViewportConstrainedPosition());
1712 // Fixed items should always have layers.
1713 ASSERT(renderer->hasLayer());
1715 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1717 // Don't need to do this for composited fixed items.
1718 if (layer->compositingState() == PaintsIntoOwnBacking)
1721 // Also don't need to do this for invisible items.
1722 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1723 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent)
1726 layer->repainter().computeRepaintRectsIncludingDescendants();
1730 bool FrameView::shouldRubberBandInDirection(ScrollDirection direction) const
1732 Page* page = frame().page();
1734 return ScrollView::shouldRubberBandInDirection(direction);
1735 return page->chrome().client().shouldRubberBandInDirection(direction);
1738 bool FrameView::isRubberBandInProgress() const
1740 if (scrollbarsSuppressed())
1743 // If the main thread updates the scroll position for this FrameView, we should return
1744 // ScrollAnimator::isRubberBandInProgress().
1745 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1746 return scrollAnimator->isRubberBandInProgress();
1751 HostWindow* FrameView::hostWindow() const
1753 Page* page = frame().page();
1756 return &page->chrome();
1759 void FrameView::repaintContentRectangle(const IntRect& r)
1761 ASSERT(repaintAllowed());
1762 ASSERT(!m_frame->ownerElement());
1764 if (m_isTrackingRepaints) {
1765 IntRect repaintRect = r;
1766 repaintRect.move(-scrollOffset());
1767 m_trackedRepaintRects.append(repaintRect);
1770 ScrollView::repaintContentRectangle(r);
1773 void FrameView::contentsResized()
1775 ScrollView::contentsResized();
1779 void FrameView::scrollbarExistenceDidChange()
1781 // We check to make sure the view is attached to a frame() as this method can
1782 // be triggered before the view is attached by LocalFrame::createView(...) setting
1783 // various values such as setScrollBarModes(...) for example. An ASSERT is
1784 // triggered when a view is layout before being attached to a frame().
1785 if (!frame().view())
1788 // Note that simply having overlay scrollbars is not sufficient to be
1789 // certain that scrollbars' presence does not impact layout. This should
1790 // also check if custom scrollbars (as reported by shouldUseCustomScrollbars)
1791 // are in use as well.
1792 // http://crbug.com/269692
1793 bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars();
1795 if (!useOverlayScrollbars && needsLayout())
1798 if (renderView() && renderView()->usesCompositing()) {
1799 renderView()->compositor()->frameViewScrollbarsExistenceDidChange();
1801 if (!useOverlayScrollbars)
1802 renderView()->compositor()->frameViewDidChangeSize();
1806 void FrameView::handleLoadCompleted()
1808 // Once loading has completed, allow autoSize one last opportunity to
1809 // reduce the size of the frame.
1810 autoSizeIfEnabled();
1813 void FrameView::scheduleRelayout()
1815 ASSERT(m_frame->view() == this);
1817 if (isSubtreeLayout()) {
1818 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1819 m_layoutSubtreeRoot = 0;
1821 if (!m_layoutSchedulingEnabled)
1825 if (!m_frame->document()->shouldScheduleLayout())
1827 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1829 if (m_hasPendingLayout)
1831 m_hasPendingLayout = true;
1832 page()->animator().scheduleVisualUpdate();
1835 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1837 for (RenderObject* r = descendant; r; r = r->container()) {
1844 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1846 ASSERT(m_frame->view() == this);
1848 RenderView* renderView = this->renderView();
1849 if (renderView && renderView->needsLayout()) {
1851 relayoutRoot->markContainingBlocksForLayout(false);
1855 if (layoutPending() || !m_layoutSchedulingEnabled) {
1856 if (m_layoutSubtreeRoot != relayoutRoot) {
1857 if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
1858 // Keep the current root
1859 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
1860 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1861 } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
1862 // Re-root at relayoutRoot
1863 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
1864 m_layoutSubtreeRoot = relayoutRoot;
1865 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1866 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1868 // Just do a full relayout
1869 if (isSubtreeLayout())
1870 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1871 m_layoutSubtreeRoot = 0;
1872 relayoutRoot->markContainingBlocksForLayout(false);
1873 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1876 } else if (m_layoutSchedulingEnabled) {
1877 m_layoutSubtreeRoot = relayoutRoot;
1878 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1879 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1880 m_hasPendingLayout = true;
1881 page()->animator().scheduleVisualUpdate();
1885 bool FrameView::layoutPending() const
1887 return m_hasPendingLayout;
1890 bool FrameView::isInPerformLayout() const
1892 ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1893 return m_inPerformLayout;
1896 bool FrameView::needsLayout() const
1898 // This can return true in cases where the document does not have a body yet.
1899 // Document::shouldScheduleLayout takes care of preventing us from scheduling
1900 // layout in that case.
1902 RenderView* renderView = this->renderView();
1903 return layoutPending()
1904 || (renderView && renderView->needsLayout())
1905 || isSubtreeLayout();
1908 void FrameView::setNeedsLayout()
1910 if (RenderView* renderView = this->renderView())
1911 renderView->setNeedsLayout();
1914 bool FrameView::isTransparent() const
1916 return m_isTransparent;
1919 void FrameView::setTransparent(bool isTransparent)
1921 m_isTransparent = isTransparent;
1922 DisableCompositingQueryAsserts disabler;
1923 if (renderView() && renderView()->layer()->hasCompositedLayerMapping())
1924 renderView()->layer()->compositedLayerMapping()->updateContentsOpaque();
1927 bool FrameView::hasOpaqueBackground() const
1929 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1932 Color FrameView::baseBackgroundColor() const
1934 return m_baseBackgroundColor;
1937 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1939 m_baseBackgroundColor = backgroundColor;
1941 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) {
1942 CompositedLayerMappingPtr compositedLayerMapping = renderView()->layer()->compositedLayerMapping();
1943 compositedLayerMapping->updateContentsOpaque();
1944 if (compositedLayerMapping->mainGraphicsLayer())
1945 compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1947 recalculateScrollbarOverlayStyle();
1950 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1952 for (LocalFrame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1953 if (FrameView* view = frame->view()) {
1954 view->setTransparent(transparent);
1955 view->setBaseBackgroundColor(backgroundColor);
1960 void FrameView::scrollToAnchor()
1962 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1966 if (!anchorNode->renderer())
1970 if (anchorNode != m_frame->document())
1971 rect = anchorNode->boundingBox();
1973 // Scroll nested layers and frames to reveal the anchor.
1974 // Align to the top and to the closest side (this matches other browsers).
1975 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1977 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1978 cache->handleScrolledToAnchor(anchorNode.get());
1980 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
1981 m_maintainScrollPositionAnchor = anchorNode;
1984 bool FrameView::updateWidgets()
1986 // This is always called from updateWidgetsTimerFired.
1987 // m_updateWidgetsTimer should only be scheduled if we have widgets to update.
1988 // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty:
1989 ASSERT(!m_widgetUpdateSet.isEmpty());
1990 if (m_nestedLayoutCount > 1 || m_widgetUpdateSet.isEmpty())
1993 // Need to swap because script will run inside the below loop and invalidate the iterator.
1994 EmbeddedObjectSet objects;
1995 objects.swap(m_widgetUpdateSet);
1997 for (EmbeddedObjectSet::iterator it = objects.begin(); it != objects.end(); ++it) {
1998 RenderEmbeddedObject& object = **it;
1999 HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
2001 // The object may have already been destroyed (thus node cleared),
2002 // but FrameView holds a manual ref, so it won't have been deleted.
2006 // No need to update if it's already crashed or known to be missing.
2007 if (object.showsUnavailablePluginIndicator())
2010 if (element->needsWidgetUpdate())
2011 element->updateWidget();
2012 object.updateWidgetPosition();
2014 // Prevent plugins from causing infinite updates of themselves.
2015 // FIXME: Do we really need to prevent this?
2016 m_widgetUpdateSet.remove(&object);
2019 return m_widgetUpdateSet.isEmpty();
2022 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
2024 ASSERT(!isInPerformLayout());
2025 RefPtr<FrameView> protect(this);
2026 m_updateWidgetsTimer.stop();
2027 for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
2028 if (updateWidgets())
2033 void FrameView::flushAnyPendingPostLayoutTasks()
2035 ASSERT(!isInPerformLayout());
2036 if (m_postLayoutTasksTimer.isActive())
2037 performPostLayoutTasks();
2038 if (m_updateWidgetsTimer.isActive())
2039 updateWidgetsTimerFired(0);
2042 void FrameView::scheduleUpdateWidgetsIfNecessary()
2044 ASSERT(!isInPerformLayout());
2045 if (m_updateWidgetsTimer.isActive() || m_widgetUpdateSet.isEmpty())
2047 m_updateWidgetsTimer.startOneShot(0, FROM_HERE);
2050 void FrameView::performPostLayoutTasks()
2052 // FIXME: We can reach here, even when the page is not active!
2053 // http/tests/inspector/elements/html-link-import.html and many other
2054 // tests hit that case.
2055 // We should ASSERT(isActive()); or at least return early if we can!
2056 ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
2057 TRACE_EVENT0("webkit", "FrameView::performPostLayoutTasks");
2058 RefPtr<FrameView> protect(this);
2060 m_postLayoutTasksTimer.stop();
2062 m_frame->selection().setCaretRectNeedsUpdate();
2065 // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
2066 DisableCompositingQueryAsserts disabler;
2067 m_frame->selection().updateAppearance();
2070 ASSERT(m_frame->document());
2071 if (m_nestedLayoutCount <= 1) {
2072 if (m_firstLayoutCallbackPending)
2073 m_firstLayoutCallbackPending = false;
2075 // Ensure that we always send this eventually.
2076 if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad())
2077 m_isVisuallyNonEmpty = true;
2079 // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2080 if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2081 m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2082 // FIXME: This callback is probably not needed, but is currently used
2083 // by android for setting the background color.
2084 m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout();
2088 FontFaceSet::didLayout(*m_frame->document());
2090 updateWidgetPositions();
2092 // Plugins could have torn down the page inside updateWidgetPositions().
2096 scheduleUpdateWidgetsIfNecessary();
2098 if (Page* page = m_frame->page()) {
2099 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2100 scrollingCoordinator->notifyLayoutUpdated();
2105 sendResizeEventIfNeeded();
2108 void FrameView::sendResizeEventIfNeeded()
2112 RenderView* renderView = this->renderView();
2113 if (!renderView || renderView->document().printing())
2116 IntSize currentSize = layoutSize(IncludeScrollbars);
2117 float currentZoomFactor = renderView->style()->zoom();
2119 bool shouldSendResizeEvent = currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor;
2121 m_lastViewportSize = currentSize;
2122 m_lastZoomFactor = currentZoomFactor;
2124 if (!shouldSendResizeEvent)
2127 m_frame->document()->enqueueResizeEvent();
2130 InspectorInstrumentation::didResizeMainFrame(m_frame->page());
2133 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2135 performPostLayoutTasks();
2138 void FrameView::updateCounters()
2140 RenderView* view = renderView();
2141 if (!view->hasRenderCounters())
2144 for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) {
2145 if (!renderer->isCounter())
2148 toRenderCounter(renderer)->updateCounter();
2152 void FrameView::autoSizeIfEnabled()
2154 if (!m_shouldAutoSize)
2160 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2162 Document* document = frame().document();
2163 if (!document || !document->isActive())
2166 Element* documentElement = document->documentElement();
2167 if (!documentElement)
2170 // If this is the first time we run autosize, start from small height and
2171 // allow it to grow.
2172 if (!m_didRunAutosize)
2173 resize(frameRect().width(), m_minAutoSize.height());
2175 IntSize size = frameRect().size();
2177 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2178 // which may result in a height change during the second iteration.
2179 for (int i = 0; i < 2; i++) {
2180 // Update various sizes including contentsSize, scrollHeight, etc.
2181 document->updateLayoutIgnorePendingStylesheets();
2183 RenderView* renderView = document->renderView();
2187 int width = renderView->minPreferredLogicalWidth();
2189 RenderBox* documentRenderBox = documentElement->renderBox();
2190 if (!documentRenderBox)
2193 int height = documentRenderBox->scrollHeight();
2194 IntSize newSize(width, height);
2196 // Check to see if a scrollbar is needed for a given dimension and
2197 // if so, increase the other dimension to account for the scrollbar.
2198 // Since the dimensions are only for the view rectangle, once a
2199 // dimension exceeds the maximum, there is no need to increase it further.
2200 if (newSize.width() > m_maxAutoSize.width()) {
2201 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2202 if (!localHorizontalScrollbar)
2203 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2204 if (!localHorizontalScrollbar->isOverlayScrollbar())
2205 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
2207 // Don't bother checking for a vertical scrollbar because the width is at
2208 // already greater the maximum.
2209 } else if (newSize.height() > m_maxAutoSize.height()) {
2210 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
2211 if (!localVerticalScrollbar)
2212 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
2213 if (!localVerticalScrollbar->isOverlayScrollbar())
2214 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
2216 // Don't bother checking for a horizontal scrollbar because the height is
2217 // already greater the maximum.
2220 // Ensure the size is at least the min bounds.
2221 newSize = newSize.expandedTo(m_minAutoSize);
2223 // Bound the dimensions by the max bounds and determine what scrollbars to show.
2224 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
2225 if (newSize.width() > m_maxAutoSize.width()) {
2226 newSize.setWidth(m_maxAutoSize.width());
2227 horizonalScrollbarMode = ScrollbarAlwaysOn;
2229 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
2230 if (newSize.height() > m_maxAutoSize.height()) {
2231 newSize.setHeight(m_maxAutoSize.height());
2232 verticalScrollbarMode = ScrollbarAlwaysOn;
2235 if (newSize == size)
2238 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
2239 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
2240 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
2241 && !m_frame->document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width()))
2244 resize(newSize.width(), newSize.height());
2245 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
2246 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
2247 setVerticalScrollbarLock(false);
2248 setHorizontalScrollbarLock(false);
2249 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
2251 m_didRunAutosize = true;
2254 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2256 if (!m_viewportRenderer)
2259 if (m_overflowStatusDirty) {
2260 m_horizontalOverflow = horizontalOverflow;
2261 m_verticalOverflow = verticalOverflow;
2262 m_overflowStatusDirty = false;
2266 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2267 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2269 if (horizontalOverflowChanged || verticalOverflowChanged) {
2270 m_horizontalOverflow = horizontalOverflow;
2271 m_verticalOverflow = verticalOverflow;
2273 RefPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow);
2274 event->setTarget(m_viewportRenderer->node());
2275 m_frame->document()->enqueueAnimationFrameEvent(event.release());
2280 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const
2282 ASSERT(m_frame->view() == this);
2284 if (paintsEntireContents())
2285 return IntRect(IntPoint(), contentsSize());
2287 // Set our clip rect to be our contents.
2288 IntRect clipRect = contentsToWindow(visibleContentRect(scrollbarInclusion));
2289 if (!m_frame->ownerElement())
2292 // Take our owner element and get its clip rect.
2293 HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement();
2294 FrameView* parentView = ownerElement->document().view();
2296 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement));
2300 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement) const
2302 // The renderer can sometimes be null when style="display:none" interacts
2303 // with external content and plugins.
2304 if (!ownerElement->renderer())
2305 return windowClipRect();
2307 // If we have no layer, just return our window clip rect.
2308 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2309 if (!enclosingLayer)
2310 return windowClipRect();
2312 // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2313 // https://code.google.com/p/chromium/issues/detail?id=343769
2314 DisableCompositingQueryAsserts disabler;
2316 // Apply the clip from the layer.
2317 IntRect clipRect = contentsToWindow(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
2318 return intersection(clipRect, windowClipRect());
2321 bool FrameView::isActive() const
2323 Page* page = frame().page();
2324 return page && page->focusController().isActive();
2327 void FrameView::scrollTo(const IntSize& newOffset)
2329 LayoutSize offset = scrollOffset();
2330 ScrollView::scrollTo(newOffset);
2331 if (offset != scrollOffset()) {
2332 updateLayersAndCompositingAfterScrollIfNeeded();
2333 scrollPositionChanged();
2335 frame().loader().client()->didChangeScrollOffset();
2338 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2340 // Add in our offset within the FrameView.
2341 IntRect dirtyRect = rect;
2342 dirtyRect.moveBy(scrollbar->location());
2344 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && isInPerformLayout()) {
2345 if (scrollbar == verticalScrollbar()) {
2346 m_verticalBarDamage = dirtyRect;
2347 m_hasVerticalBarDamage = true;
2349 m_horizontalBarDamage = dirtyRect;
2350 m_hasHorizontalBarDamage = true;
2353 invalidateRect(dirtyRect);
2357 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2359 if (!m_tickmarks.isEmpty())
2360 tickmarks = m_tickmarks;
2362 tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch);
2365 IntRect FrameView::windowResizerRect() const
2367 Page* page = frame().page();
2370 return page->chrome().windowResizerRect();
2373 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
2375 if (m_visibleContentScaleFactor == visibleContentScaleFactor)
2378 m_visibleContentScaleFactor = visibleContentScaleFactor;
2379 updateScrollbars(scrollOffset());
2382 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2384 m_inputEventsOffsetForEmulation = offset;
2385 m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2388 IntSize FrameView::inputEventsOffsetForEmulation() const
2390 return m_inputEventsOffsetForEmulation;
2393 float FrameView::inputEventsScaleFactor() const
2395 return visibleContentScaleFactor() * m_inputEventsScaleFactorForEmulation;
2398 bool FrameView::scrollbarsCanBeActive() const
2400 if (m_frame->view() != this)
2403 return !!m_frame->document();
2406 IntRect FrameView::scrollableAreaBoundingBox() const
2408 RenderPart* ownerRenderer = frame().ownerRenderer();
2412 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
2415 bool FrameView::isScrollable()
2418 // 1) If there an actual overflow.
2419 // 2) display:none or visibility:hidden set to self or inherited.
2420 // 3) overflow{-x,-y}: hidden;
2421 // 4) scrolling: no;
2424 IntSize contentsSize = this->contentsSize();
2425 IntSize visibleContentSize = visibleContentRect().size();
2426 if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2430 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2431 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
2435 ScrollbarMode horizontalMode;
2436 ScrollbarMode verticalMode;
2437 calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly);
2438 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2444 void FrameView::updateScrollableAreaSet()
2446 // That ensures that only inner frames are cached.
2447 FrameView* parentFrameView = this->parentFrameView();
2448 if (!parentFrameView)
2451 if (!isScrollable()) {
2452 parentFrameView->removeScrollableArea(this);
2456 parentFrameView->addScrollableArea(this);
2459 bool FrameView::shouldSuspendScrollAnimations() const
2461 return m_frame->loader().state() != FrameStateComplete;
2464 void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate)
2470 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
2473 void FrameView::notifyPageThatContentAreaWillPaint() const
2475 Page* page = m_frame->page();
2479 contentAreaWillPaint();
2481 if (!m_scrollableAreas)
2484 for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) {
2485 ScrollableArea* scrollableArea = *it;
2487 if (!scrollableArea->scrollbarsCanBeActive())
2490 scrollableArea->contentAreaWillPaint();
2494 bool FrameView::scrollAnimatorEnabled() const
2496 return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled();
2499 void FrameView::updateAnnotatedRegions()
2501 Document* document = m_frame->document();
2502 if (!document->hasAnnotatedRegions())
2504 Vector<AnnotatedRegionValue> newRegions;
2505 document->renderBox()->collectAnnotatedRegions(newRegions);
2506 if (newRegions == document->annotatedRegions())
2508 document->setAnnotatedRegions(newRegions);
2509 if (Page* page = m_frame->page())
2510 page->chrome().client().annotatedRegionsChanged();
2513 void FrameView::updateScrollCorner()
2515 RefPtr<RenderStyle> cornerStyle;
2516 IntRect cornerRect = scrollCornerRect();
2517 Document* doc = m_frame->document();
2519 if (doc && !cornerRect.isEmpty()) {
2520 // Try the <body> element first as a scroll corner source.
2521 if (Element* body = doc->body()) {
2522 if (RenderObject* renderer = body->renderer())
2523 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2527 // If the <body> didn't have a custom style, then the root element might.
2528 if (Element* docElement = doc->documentElement()) {
2529 if (RenderObject* renderer = docElement->renderer())
2530 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2535 // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
2536 if (RenderPart* renderer = m_frame->ownerRenderer())
2537 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2542 if (!m_scrollCorner)
2543 m_scrollCorner = RenderScrollbarPart::createAnonymous(doc);
2544 m_scrollCorner->setStyle(cornerStyle.release());
2545 invalidateScrollCorner(cornerRect);
2546 } else if (m_scrollCorner) {
2547 m_scrollCorner->destroy();
2551 ScrollView::updateScrollCorner();
2554 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
2556 if (context->updatingControlTints()) {
2557 updateScrollCorner();
2561 if (m_scrollCorner) {
2562 bool needsBackgorund = isMainFrame();
2563 if (needsBackgorund)
2564 context->fillRect(cornerRect, baseBackgroundColor());
2565 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
2569 ScrollView::paintScrollCorner(context, cornerRect);
2572 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
2574 bool needsBackgorund = bar->isCustomScrollbar() && isMainFrame();
2575 if (needsBackgorund) {
2576 IntRect toFill = bar->frameRect();
2577 toFill.intersect(rect);
2578 context->fillRect(toFill, baseBackgroundColor());
2581 ScrollView::paintScrollbar(context, bar, rect);
2584 Color FrameView::documentBackgroundColor() const
2586 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2587 // the document and the body against the base background color of the frame view.
2588 // Background images are unfortunately impractical to include.
2590 Color result = baseBackgroundColor();
2591 if (!frame().document())
2594 Element* htmlElement = frame().document()->documentElement();
2595 Element* bodyElement = frame().document()->body();
2597 // We take the aggregate of the base background color
2598 // the <html> background color, and the <body>
2599 // background color to find the document color. The
2600 // addition of the base background color is not
2601 // technically part of the document background, but it
2602 // otherwise poses problems when the aggregate is not
2604 if (htmlElement && htmlElement->renderer())
2605 result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2606 if (bodyElement && bodyElement->renderer())
2607 result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2612 bool FrameView::hasCustomScrollbars() const
2614 const HashSet<RefPtr<Widget> >* viewChildren = children();
2615 HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
2616 for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
2617 Widget* widget = current->get();
2618 if (widget->isFrameView()) {
2619 if (toFrameView(widget)->hasCustomScrollbars())
2621 } else if (widget->isScrollbar()) {
2622 Scrollbar* scrollbar = static_cast<Scrollbar*>(widget);
2623 if (scrollbar->isCustomScrollbar())
2631 FrameView* FrameView::parentFrameView() const
2636 if (LocalFrame* parentFrame = m_frame->tree().parent())
2637 return parentFrame->view();
2642 void FrameView::updateControlTints()
2644 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
2645 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
2646 // This is only done if the theme supports control tinting. It's up to the theme and platform
2647 // to define when controls get the tint and to call this function when that changes.
2649 // Optimize the common case where we bring a window to the front while it's still empty.
2650 if (m_frame->document()->url().isEmpty())
2653 // FIXME: We shouldn't rely on the paint code to implement :window-inactive on custom scrollbars.
2654 if (!RenderTheme::theme().supportsControlTints() && !hasCustomScrollbars())
2657 // Updating layout can run script, which can tear down the FrameView.
2658 RefPtr<FrameView> protector(this);
2659 updateLayoutAndStyleForPainting();
2661 // FIXME: The use of paint seems like overkill: crbug.com/236892
2662 GraphicsContext context(0); // NULL canvas to get a non-painting context.
2663 context.setUpdatingControlTints(true);
2664 paint(&context, frameRect());
2667 bool FrameView::wasScrolledByUser() const
2669 return m_wasScrolledByUser;
2672 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
2674 if (m_inProgrammaticScroll)
2676 m_maintainScrollPositionAnchor = nullptr;
2677 m_wasScrolledByUser = wasScrolledByUser;
2680 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
2682 Document* document = m_frame->document();
2686 if (document->printing())
2687 fillWithRed = false; // Printing, don't fill with red (can't remember why).
2688 else if (m_frame->ownerElement())
2689 fillWithRed = false; // Subframe, don't fill with red.
2690 else if (isTransparent())
2691 fillWithRed = false; // Transparent, don't fill with red.
2692 else if (m_paintBehavior & PaintBehaviorSelectionOnly)
2693 fillWithRed = false; // Selections are transparent, don't fill with red.
2694 else if (m_nodeToDraw)
2695 fillWithRed = false; // Element images are transparent, don't fill with red.
2700 p->fillRect(rect, Color(0xFF, 0, 0));
2703 RenderView* renderView = this->renderView();
2705 WTF_LOG_ERROR("called FrameView::paint with nil renderer");
2709 ASSERT(!needsLayout());
2713 InspectorInstrumentation::willPaint(renderView, 0);
2715 bool isTopLevelPainter = !s_inPaintContents;
2716 s_inPaintContents = true;
2718 FontCachePurgePreventer fontCachePurgePreventer;
2720 PaintBehavior oldPaintBehavior = m_paintBehavior;
2722 if (FrameView* parentView = parentFrameView()) {
2723 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
2724 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2727 if (m_paintBehavior == PaintBehaviorNormal)
2728 document->markers().invalidateRenderedRectsForMarkersInRect(rect);
2730 if (document->printing())
2731 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2733 ASSERT(!m_isPainting);
2734 m_isPainting = true;
2736 // m_nodeToDraw is used to draw only one element (and its descendants)
2737 RenderObject* renderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
2738 RenderLayer* rootLayer = renderView->layer();
2741 renderView->assertSubtreeIsLaidOut();
2742 RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(rootLayer->renderer());
2745 RenderObject* enclosingLayerRenderer = renderer ? renderer->enclosingLayer()->renderer() : 0;
2746 rootLayer->paint(p, rect, m_paintBehavior, enclosingLayerRenderer);
2748 if (rootLayer->containsDirtyOverlayScrollbars())
2749 rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, renderer);
2751 m_isPainting = false;
2753 m_paintBehavior = oldPaintBehavior;
2754 m_lastPaintTime = currentTime();
2756 // Regions may have changed as a result of the visibility/z-index of element changing.
2757 if (document->annotatedRegionsDirty())
2758 updateAnnotatedRegions();
2760 if (isTopLevelPainter) {
2761 // Everythin that happens after paintContents completions is considered
2762 // to be part of the next frame.
2763 s_currentFrameTimeStamp = currentTime();
2764 s_inPaintContents = false;
2767 InspectorInstrumentation::didPaint(renderView, 0, p, rect);
2770 void FrameView::setPaintBehavior(PaintBehavior behavior)
2772 m_paintBehavior = behavior;
2775 PaintBehavior FrameView::paintBehavior() const
2777 return m_paintBehavior;
2780 bool FrameView::isPainting() const
2782 return m_isPainting;
2785 void FrameView::setNodeToDraw(Node* node)
2787 m_nodeToDraw = node;
2790 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
2792 if (context->paintingDisabled())
2795 if (m_frame->document()->printing())
2798 if (isMainFrame()) {
2799 if (m_frame->page()->chrome().client().paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect))
2803 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
2806 void FrameView::updateLayoutAndStyleForPainting()
2808 // Updating layout can run script, which can tear down the FrameView.
2809 RefPtr<FrameView> protector(this);
2811 updateLayoutAndStyleIfNeededRecursive();
2812 if (RenderView* view = renderView()) {
2813 ASSERT(!view->needsLayout());
2814 view->compositor()->updateCompositingLayers();
2816 // FIXME: we should not have any dirty bits left at this point. Unfortunately, this is not yet the case because
2817 // the code in updateCompositingLayers sometimes creates new dirty bits when updating direct compositing reasons.
2818 // See crbug.com/354100.
2819 view->compositor()->scheduleAnimationIfNeeded();
2822 scrollContentsIfNeededRecursive();
2825 void FrameView::updateLayoutAndStyleIfNeededRecursive()
2827 // We have to crawl our entire tree looking for any FrameViews that need
2828 // layout and make sure they are up to date.
2829 // Mac actually tests for intersection with the dirty region and tries not to
2830 // update layout for frames that are outside the dirty region. Not only does this seem
2831 // pointless (since those frames will have set a zero timer to layout anyway), but
2832 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2833 // region but then become included later by the second frame adding rects to the dirty region
2834 // when it lays out.
2836 m_frame->document()->updateRenderTreeIfNeeded();
2841 // FIXME: Calling layout() shouldn't trigger scripe execution or have any
2842 // observable effects on the frame tree but we're not quite there yet.
2843 Vector<RefPtr<FrameView> > frameViews;
2844 for (LocalFrame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2845 if (FrameView* view = child->view())
2846 frameViews.append(view);
2849 const Vector<RefPtr<FrameView> >::iterator end = frameViews.end();
2850 for (Vector<RefPtr<FrameView> >::iterator it = frameViews.begin(); it != end; ++it)
2851 (*it)->updateLayoutAndStyleIfNeededRecursive();
2853 // This assert ensures that parent frames are clean, when child frames finished updating layout and style.
2854 ASSERT(!needsLayout());
2857 void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize)
2859 ASSERT(!enable || !minSize.isEmpty());
2860 ASSERT(minSize.width() <= maxSize.width());
2861 ASSERT(minSize.height() <= maxSize.height());
2863 if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize)
2867 m_shouldAutoSize = enable;
2868 m_minAutoSize = minSize;
2869 m_maxAutoSize = maxSize;
2870 m_didRunAutosize = false;
2872 setLayoutSizeFixedToFrameSize(enable);
2875 if (m_shouldAutoSize)
2878 // Since autosize mode forces the scrollbar mode, change them to being auto.
2879 setVerticalScrollbarLock(false);
2880 setHorizontalScrollbarLock(false);
2881 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
2884 void FrameView::forceLayout(bool allowSubtree)
2886 layout(allowSubtree);
2889 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2891 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2892 // the state of things before and after the layout
2893 if (RenderView* renderView = this->renderView()) {
2894 float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2895 float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2897 LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2898 LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2899 renderView->setLogicalWidth(flooredPageLogicalWidth);
2900 renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2901 renderView->setNeedsLayoutAndPrefWidthsRecalc();
2904 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2905 // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2906 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
2907 // implementation should not do this!
2908 bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode();
2909 const LayoutRect& documentRect = renderView->documentRect();
2910 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2911 if (docLogicalWidth > pageLogicalWidth) {
2912 FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor));
2913 FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize);
2914 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2915 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2917 flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2918 flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2919 renderView->setLogicalWidth(flooredPageLogicalWidth);
2920 renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2921 renderView->setNeedsLayoutAndPrefWidthsRecalc();
2924 const LayoutRect& updatedDocumentRect = renderView->documentRect();
2925 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2926 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2927 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2928 LayoutUnit clippedLogicalLeft = 0;
2929 if (!renderView->style()->isLeftToRightDirection())
2930 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2931 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2933 if (!horizontalWritingMode)
2934 overflow = overflow.transposedRect();
2935 renderView->clearLayoutOverflow();
2936 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2943 IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const
2945 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
2947 // Convert from page ("absolute") to FrameView coordinates.
2948 rect.moveBy(-scrollPosition());
2953 IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const
2955 IntRect rect = viewRect;
2957 // Convert from FrameView coords into page ("absolute") coordinates.
2958 rect.moveBy(scrollPosition());
2960 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2961 // move the rect for now.
2962 rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms)));
2966 IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const
2968 IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms));
2970 // Convert from page ("absolute") to FrameView coordinates.
2971 point.moveBy(-scrollPosition());
2975 IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const
2977 IntPoint point = viewPoint;
2979 // Convert from FrameView coords into page ("absolute") coordinates.
2980 point += IntSize(scrollX(), scrollY());
2982 return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms));
2985 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2987 if (const ScrollView* parentScrollView = toScrollView(parent())) {
2988 if (parentScrollView->isFrameView()) {
2989 const FrameView* parentView = toFrameView(parentScrollView);
2990 // Get our renderer in the parent view
2991 RenderPart* renderer = m_frame->ownerRenderer();
2995 IntRect rect(localRect);
2996 // Add borders and padding??
2997 rect.move(renderer->borderLeft() + renderer->paddingLeft(),
2998 renderer->borderTop() + renderer->paddingTop());
2999 return parentView->convertFromRenderer(renderer, rect);
3002 return Widget::convertToContainingView(localRect);
3008 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
3010 if (const ScrollView* parentScrollView = toScrollView(parent())) {
3011 if (parentScrollView->isFrameView()) {
3012 const FrameView* parentView = toFrameView(parentScrollView);
3014 // Get our renderer in the parent view
3015 RenderPart* renderer = m_frame->ownerRenderer();
3019 IntRect rect = parentView->convertToRenderer(renderer, parentRect);
3020 // Subtract borders and padding
3021 rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
3022 -renderer->borderTop() - renderer->paddingTop());
3026 return Widget::convertFromContainingView(parentRect);
3032 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
3034 if (const ScrollView* parentScrollView = toScrollView(parent())) {
3035 if (parentScrollView->isFrameView()) {
3036 const FrameView* parentView = toFrameView(parentScrollView);
3038 // Get our renderer in the parent view
3039 RenderPart* renderer = m_frame->ownerRenderer();
3043 IntPoint point(localPoint);
3045 // Add borders and padding
3046 point.move(renderer->borderLeft() + renderer->paddingLeft(),
3047 renderer->borderTop() + renderer->paddingTop());
3048 return parentView->convertFromRenderer(renderer, point);
3051 return Widget::convertToContainingView(localPoint);
3057 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
3059 if (const ScrollView* parentScrollView = toScrollView(parent())) {
3060 if (parentScrollView->isFrameView()) {
3061 const FrameView* parentView = toFrameView(parentScrollView);
3063 // Get our renderer in the parent view
3064 RenderPart* renderer = m_frame->ownerRenderer();
3068 IntPoint point = parentView->convertToRenderer(renderer, parentPoint);
3069 // Subtract borders and padding
3070 point.move(-renderer->borderLeft() - renderer->paddingLeft(),
3071 -renderer->borderTop() - renderer->paddingTop());
3075 return Widget::convertFromContainingView(parentPoint);
3081 void FrameView::setTracksRepaints(bool trackRepaints)
3083 if (trackRepaints == m_isTrackingRepaints)
3086 for (LocalFrame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
3087 if (RenderView* renderView = frame->contentRenderer())
3088 renderView->compositor()->setTracksRepaints(trackRepaints);
3091 resetTrackedRepaints();
3092 m_isTrackingRepaints = trackRepaints;
3095 void FrameView::resetTrackedRepaints()
3097 m_trackedRepaintRects.clear();
3098 if (RenderView* renderView = this->renderView())
3099 renderView->compositor()->resetTrackedRepaintRects();
3102 String FrameView::trackedRepaintRectsAsText() const
3105 if (!m_trackedRepaintRects.isEmpty()) {
3106 ts << "(repaint rects\n";
3107 for (size_t i = 0; i < m_trackedRepaintRects.size(); ++i)
3108 ts << " (rect " << m_trackedRepaintRects[i].x() << " " << m_trackedRepaintRects[i].y() << " " << m_trackedRepaintRects[i].width() << " " << m_trackedRepaintRects[i].height() << ")\n";
3111 return ts.release();
3114 void FrameView::addResizerArea(RenderBox* resizerBox)
3116 if (!m_resizerAreas)
3117 m_resizerAreas = adoptPtr(new ResizerAreaSet);
3118 m_resizerAreas->add(resizerBox);
3121 void FrameView::removeResizerArea(RenderBox* resizerBox)
3123 if (!m_resizerAreas)
3126 ResizerAreaSet::iterator it = m_resizerAreas->find(resizerBox);
3127 if (it != m_resizerAreas->end())
3128 m_resizerAreas->remove(it);
3131 bool FrameView::addScrollableArea(ScrollableArea* scrollableArea)
3133 ASSERT(scrollableArea);
3134 if (!m_scrollableAreas)
3135 m_scrollableAreas = adoptPtr(new ScrollableAreaSet);
3136 return m_scrollableAreas->add(scrollableArea).isNewEntry;
3139 bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
3141 if (!m_scrollableAreas)
3144 ScrollableAreaSet::iterator it = m_scrollableAreas->find(scrollableArea);
3145 if (it == m_scrollableAreas->end())
3148 m_scrollableAreas->remove(it);
3152 bool FrameView::containsScrollableArea(const ScrollableArea* scrollableArea) const
3154 ASSERT(scrollableArea);
3155 if (!m_scrollableAreas || !scrollableArea)
3157 return m_scrollableAreas->contains(const_cast<ScrollableArea*>(scrollableArea));
3160 void FrameView::removeChild(Widget* widget)
3162 if (widget->isFrameView())
3163 removeScrollableArea(toFrameView(widget));
3165 ScrollView::removeChild(widget);
3168 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
3170 // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
3171 // should handle wheel events.
3172 #if !USE(RUBBER_BANDING)
3173 if (!isScrollable())
3177 // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
3178 if (!canHaveScrollbars())
3181 return ScrollableArea::handleWheelEvent(wheelEvent);
3184 bool FrameView::isVerticalDocument() const
3186 RenderView* renderView = this->renderView();
3190 return renderView->style()->isHorizontalWritingMode();
3193 bool FrameView::isFlippedDocument() const
3195 RenderView* renderView = this->renderView();
3199 return renderView->style()->isFlippedBlocksWritingMode();
3202 AXObjectCache* FrameView::axObjectCache() const
3204 if (frame().document())
3205 return frame().document()->existingAXObjectCache();
3209 void FrameView::setCursor(const Cursor& cursor)
3211 Page* page = frame().page();
3214 page->chrome().setCursor(cursor);
3217 bool FrameView::isMainFrame() const
3219 return m_frame->isMainFrame();
3222 void FrameView::frameRectsChanged()
3224 if (layoutSizeFixedToFrameSize())
3225 setLayoutSizeInternal(frameRect().size());
3227 ScrollView::frameRectsChanged();
3230 void FrameView::setLayoutSizeInternal(const IntSize& size)
3232 if (m_layoutSize == size)
3235 m_layoutSize = size;
3239 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3241 ScrollableArea::didAddScrollbar(scrollbar, orientation);
3242 if (AXObjectCache* cache = axObjectCache())
3243 cache->handleScrollbarUpdate(this);
3246 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3248 ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
3249 if (AXObjectCache* cache = axObjectCache()) {
3250 cache->remove(scrollbar);
3251 cache->handleScrollbarUpdate(this);
3255 } // namespace WebCore