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/animation/DocumentAnimations.h"
34 #include "core/css/FontFaceSet.h"
35 #include "core/css/resolver/StyleResolver.h"
36 #include "core/dom/DocumentMarkerController.h"
37 #include "core/editing/FrameSelection.h"
38 #include "core/events/OverflowEvent.h"
39 #include "core/fetch/ResourceFetcher.h"
40 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
41 #include "core/frame/Frame.h"
42 #include "core/frame/Settings.h"
43 #include "core/html/HTMLFrameElement.h"
44 #include "core/html/HTMLPlugInElement.h"
45 #include "core/html/parser/TextResourceDecoder.h"
46 #include "core/inspector/InspectorInstrumentation.h"
47 #include "core/loader/FrameLoader.h"
48 #include "core/loader/FrameLoaderClient.h"
49 #include "core/page/Chrome.h"
50 #include "core/page/ChromeClient.h"
51 #include "core/page/EventHandler.h"
52 #include "core/page/FocusController.h"
53 #include "core/page/FrameTree.h"
54 #include "core/page/scrolling/ScrollingCoordinator.h"
55 #include "core/rendering/CompositedLayerMapping.h"
56 #include "core/rendering/FastTextAutosizer.h"
57 #include "core/rendering/RenderCounter.h"
58 #include "core/rendering/RenderEmbeddedObject.h"
59 #include "core/rendering/RenderLayer.h"
60 #include "core/rendering/RenderLayerCompositor.h"
61 #include "core/rendering/RenderListBox.h"
62 #include "core/rendering/RenderPart.h"
63 #include "core/rendering/RenderScrollbar.h"
64 #include "core/rendering/RenderScrollbarPart.h"
65 #include "core/rendering/RenderTheme.h"
66 #include "core/rendering/RenderView.h"
67 #include "core/rendering/RenderWidget.h"
68 #include "core/rendering/TextAutosizer.h"
69 #include "core/rendering/style/RenderStyle.h"
70 #include "core/rendering/svg/RenderSVGRoot.h"
71 #include "core/svg/SVGDocument.h"
72 #include "core/svg/SVGSVGElement.h"
73 #include "platform/TraceEvent.h"
74 #include "platform/fonts/FontCache.h"
75 #include "platform/geometry/FloatRect.h"
76 #include "platform/graphics/GraphicsContext.h"
77 #include "platform/graphics/GraphicsLayerDebugInfo.h"
78 #include "platform/scroll/ScrollAnimator.h"
79 #include "platform/scroll/ScrollbarTheme.h"
80 #include "platform/text/TextStream.h"
81 #include "wtf/CurrentTime.h"
82 #include "wtf/TemporaryChange.h"
86 using namespace HTMLNames;
88 double FrameView::s_currentFrameTimeStamp = 0.0;
89 bool FrameView::s_inPaintContents = false;
91 // The maximum number of updateWidgets iterations that should be done before returning.
92 static const unsigned maxUpdateWidgetsIterations = 2;
93 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
95 static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint)
97 RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags;
100 flags &= ~RenderLayer::CheckForRepaint;
101 flags |= RenderLayer::NeedsFullRepaintInBacking;
103 if (isRelayoutingSubtree && layer->isPaginated())
104 flags |= RenderLayer::UpdatePagination;
108 FrameView::FrameView(Frame* frame)
110 , m_canHaveScrollbars(true)
111 , m_slowRepaintObjectCount(0)
112 , m_hasPendingLayout(false)
113 , m_layoutSubtreeRoot(0)
114 , m_inSynchronousPostLayout(false)
115 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
116 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
117 , m_isTransparent(false)
118 , m_baseBackgroundColor(Color::white)
119 , m_mediaType("screen")
120 , m_overflowStatusDirty(true)
121 , m_viewportRenderer(0)
122 , m_wasScrolledByUser(false)
123 , m_inProgrammaticScroll(false)
124 , m_safeToPropagateScrollToParent(true)
125 , m_isTrackingRepaints(false)
127 , m_shouldAutoSize(false)
128 , m_inAutoSize(false)
129 , m_didRunAutosize(false)
130 , m_hasSoftwareFilters(false)
131 , m_servicingAnimations(false)
132 , m_visibleContentScaleFactor(1)
133 , m_inputEventsScaleFactorForEmulation(1)
135 , m_layoutSizeFixedToFrameSize(true)
136 , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
144 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
145 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed);
148 PassRefPtr<FrameView> FrameView::create(Frame* frame)
150 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
152 return view.release();
155 PassRefPtr<FrameView> FrameView::create(Frame* frame, const IntSize& initialSize)
157 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
158 view->Widget::setFrameRect(IntRect(view->location(), initialSize));
159 view->setLayoutSizeInternal(initialSize);
162 return view.release();
165 FrameView::~FrameView()
167 if (m_postLayoutTasksTimer.isActive())
168 m_postLayoutTasksTimer.stop();
170 if (m_didScrollTimer.isActive())
171 m_didScrollTimer.stop();
173 removeFromAXObjectCache();
176 // Custom scrollbars should already be destroyed at this point
177 ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
178 ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
180 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
181 setHasVerticalScrollbar(false);
183 ASSERT(!m_scrollCorner);
186 ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
187 RenderPart* renderer = m_frame->ownerRenderer();
188 if (renderer && renderer->widget() == this)
189 renderer->setWidget(0);
192 void FrameView::reset()
194 m_cannotBlitToWindow = false;
195 m_isOverlapped = false;
196 m_contentIsOpaque = false;
197 m_hasPendingLayout = false;
198 m_layoutSubtreeRoot = 0;
199 m_doFullRepaint = false;
200 m_layoutSchedulingEnabled = true;
201 m_inPerformLayout = false;
202 m_canRepaintDuringPerformLayout = false;
203 m_doingPreLayoutStyleUpdate = false;
204 m_inSynchronousPostLayout = false;
206 m_nestedLayoutCount = 0;
207 m_postLayoutTasksTimer.stop();
208 m_updateWidgetsTimer.stop();
209 m_firstLayout = true;
210 m_firstLayoutCallbackPending = false;
211 m_wasScrolledByUser = false;
212 m_safeToPropagateScrollToParent = true;
213 m_lastViewportSize = IntSize();
214 m_lastZoomFactor = 1.0f;
215 m_isTrackingRepaints = false;
216 m_trackedRepaintRects.clear();
218 m_paintBehavior = PaintBehaviorNormal;
219 m_isPainting = false;
220 m_visuallyNonEmptyCharacterCount = 0;
221 m_visuallyNonEmptyPixelCount = 0;
222 m_isVisuallyNonEmpty = false;
223 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
224 m_maintainScrollPositionAnchor = 0;
225 m_partialLayout.reset();
226 m_viewportConstrainedObjects.clear();
229 void FrameView::removeFromAXObjectCache()
231 if (AXObjectCache* cache = axObjectCache())
235 void FrameView::resetScrollbars()
237 // Reset the document's scrollbars back to our defaults before we yield the floor.
238 m_firstLayout = true;
239 setScrollbarsSuppressed(true);
240 if (m_canHaveScrollbars)
241 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
243 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
244 setScrollbarsSuppressed(false);
247 void FrameView::init()
251 m_size = LayoutSize();
253 // Propagate the marginwidth/height and scrolling modes to the view.
254 Element* ownerElement = m_frame->ownerElement();
255 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
256 HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
257 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
258 setCanHaveScrollbars(false);
262 void FrameView::prepareForDetach()
264 RELEASE_ASSERT(!isInPerformLayout());
266 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
267 scrollAnimator->cancelAnimations();
269 detachCustomScrollbars();
270 // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
271 // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
272 removeFromAXObjectCache();
274 if (m_frame->page()) {
275 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
276 scrollingCoordinator->willDestroyScrollableArea(this);
280 void FrameView::detachCustomScrollbars()
282 Scrollbar* horizontalBar = horizontalScrollbar();
283 if (horizontalBar && horizontalBar->isCustomScrollbar())
284 setHasHorizontalScrollbar(false);
286 Scrollbar* verticalBar = verticalScrollbar();
287 if (verticalBar && verticalBar->isCustomScrollbar())
288 setHasVerticalScrollbar(false);
290 if (m_scrollCorner) {
291 m_scrollCorner->destroy();
296 void FrameView::recalculateScrollbarOverlayStyle()
298 ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
299 ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
301 Color backgroundColor = documentBackgroundColor();
302 // Reduce the background color from RGB to a lightness value
303 // and determine which scrollbar style to use based on a lightness
305 double hue, saturation, lightness;
306 backgroundColor.getHSL(hue, saturation, lightness);
308 overlayStyle = ScrollbarOverlayStyleLight;
310 if (oldOverlayStyle != overlayStyle)
311 setScrollbarOverlayStyle(overlayStyle);
314 void FrameView::clear()
316 setCanBlitOnScroll(true);
320 setScrollbarsSuppressed(true);
323 bool FrameView::didFirstLayout() const
325 return !m_firstLayout;
328 void FrameView::invalidateRect(const IntRect& rect)
331 if (HostWindow* window = hostWindow())
332 window->invalidateContentsAndRootView(rect);
336 RenderPart* renderer = m_frame->ownerRenderer();
340 IntRect repaintRect = rect;
341 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
342 renderer->borderTop() + renderer->paddingTop());
343 renderer->repaintRectangle(repaintRect);
346 void FrameView::setFrameRect(const IntRect& newRect)
348 IntRect oldRect = frameRect();
349 if (newRect == oldRect)
352 // Autosized font sizes depend on the width of the viewing area.
353 if (newRect.width() != oldRect.width()) {
355 Page* page = m_frame->page();
356 bool textAutosizingEnabled = m_frame->settings()->textAutosizingEnabled();
357 if (textAutosizingEnabled) {
358 TextAutosizer* textAutosizer = m_frame->document()->textAutosizer();
360 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext())
361 textAutosizer->recalculateMultipliers();
367 ScrollView::setFrameRect(newRect);
369 updateScrollableAreaSet();
371 if (RenderView* renderView = this->renderView()) {
372 if (renderView->usesCompositing())
373 renderView->compositor()->frameViewDidChangeSize();
376 viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
379 bool FrameView::scheduleAnimation()
381 if (HostWindow* window = hostWindow()) {
382 window->scheduleAnimation();
388 RenderView* FrameView::renderView() const
390 return frame().contentRenderer();
393 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
395 m_canHaveScrollbars = canHaveScrollbars;
396 ScrollView::setCanHaveScrollbars(canHaveScrollbars);
399 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, Frame*& customScrollbarFrame)
401 customScrollbarElement = 0;
402 customScrollbarFrame = 0;
404 if (Settings* settings = m_frame->settings()) {
405 if (!settings->allowCustomScrollbarInMainFrame() && isMainFrame())
409 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
410 Document* doc = m_frame->document();
412 // Try the <body> element first as a scrollbar source.
413 Element* body = doc ? doc->body() : 0;
414 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
415 customScrollbarElement = body;
419 // If the <body> didn't have a custom style, then the root element might.
420 Element* docElement = doc ? doc->documentElement() : 0;
421 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
422 customScrollbarElement = docElement;
426 // If we have an owning ipage/Frame element, then it can set the custom scrollbar also.
427 RenderPart* frameRenderer = m_frame->ownerRenderer();
428 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) {
429 customScrollbarFrame = m_frame.get();
436 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
438 Element* customScrollbarElement = 0;
439 Frame* customScrollbarFrame = 0;
440 if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
441 return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
443 // Nobody set a custom style, so we just use a native scrollbar.
444 return ScrollView::createScrollbar(orientation);
447 void FrameView::setContentsSize(const IntSize& size)
449 if (size == contentsSize())
452 ScrollView::setContentsSize(size);
453 ScrollView::contentsResized();
455 Page* page = frame().page();
459 updateScrollableAreaSet();
461 page->chrome().contentsSizeChanged(m_frame.get(), size);
464 void FrameView::adjustViewSize()
466 RenderView* renderView = this->renderView();
470 ASSERT(m_frame->view() == this);
472 const IntRect rect = renderView->documentRect();
473 const IntSize& size = rect.size();
474 ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
476 setContentsSize(size);
479 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
481 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
482 // overflow:hidden and overflow:scroll on <body> as applying to the document's
483 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
484 // use the root element.
486 EOverflow overflowX = o->style()->overflowX();
487 EOverflow overflowY = o->style()->overflowY();
489 if (o->isSVGRoot()) {
490 // overflow is ignored in stand-alone SVG documents.
491 if (!toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument())
497 bool ignoreOverflowHidden = false;
498 if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame())
499 ignoreOverflowHidden = true;
503 if (!ignoreOverflowHidden)
504 hMode = ScrollbarAlwaysOff;
507 hMode = ScrollbarAlwaysOn;
510 hMode = ScrollbarAuto;
513 // Don't set it at all.
519 if (!ignoreOverflowHidden)
520 vMode = ScrollbarAlwaysOff;
523 vMode = ScrollbarAlwaysOn;
526 vMode = ScrollbarAuto;
529 // Don't set it at all.
533 m_viewportRenderer = o;
536 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
538 m_viewportRenderer = 0;
540 const HTMLFrameOwnerElement* owner = m_frame->ownerElement();
541 if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
542 hMode = ScrollbarAlwaysOff;
543 vMode = ScrollbarAlwaysOff;
547 if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
548 hMode = ScrollbarAuto;
549 vMode = ScrollbarAuto;
551 hMode = ScrollbarAlwaysOff;
552 vMode = ScrollbarAlwaysOff;
555 if (!isSubtreeLayout()) {
556 Document* document = m_frame->document();
557 Node* body = document->body();
558 if (body && body->renderer() && body->hasTagName(framesetTag)) {
559 vMode = ScrollbarAlwaysOff;
560 hMode = ScrollbarAlwaysOff;
561 } else if (Element* viewportElement = document->viewportDefiningElement()) {
562 if (RenderObject* viewportRenderer = viewportElement->renderer()) {
563 if (viewportRenderer->style())
564 applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode);
570 void FrameView::updateCompositingLayersAfterStyleChange()
572 TRACE_EVENT0("webkit", "FrameView::updateCompositingLayersAfterStyleChange");
573 RenderView* renderView = this->renderView();
577 // If we expect to update compositing after an incipient layout, don't do so here.
578 if (m_doingPreLayoutStyleUpdate || layoutPending() || renderView->needsLayout())
581 // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues
582 // https://code.google.com/p/chromium/issues/detail?id=343756
583 DisableCompositingQueryAsserts disabler;
585 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
586 renderView->compositor()->cacheAcceleratedCompositingFlags();
588 // Sometimes we will change a property (for example, z-index) that will not
589 // cause a layout, but will require us to update compositing state. We only
590 // need to do this if a layout is not already scheduled.
592 renderView->compositor()->updateCompositingRequirementsState();
594 renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterStyleChange);
597 void FrameView::updateCompositingLayersAfterLayout()
599 TRACE_EVENT0("webkit", "FrameView::updateCompositingLayersAfterLayout");
600 RenderView* renderView = this->renderView();
604 // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues
605 // https://code.google.com/p/chromium/issues/detail?id=343756
606 DisableCompositingQueryAsserts disabler;
608 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
609 renderView->compositor()->cacheAcceleratedCompositingFlags();
610 renderView->compositor()->updateCompositingRequirementsState();
611 renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterLayout);
614 bool FrameView::usesCompositedScrolling() const
616 RenderView* renderView = this->renderView();
619 if (m_frame->settings() && m_frame->settings()->compositedScrollingForFramesEnabled())
620 return renderView->compositor()->inForcedCompositingMode();
624 GraphicsLayer* FrameView::layerForScrolling() const
626 RenderView* renderView = this->renderView();
629 return renderView->compositor()->scrollLayer();
632 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
634 RenderView* renderView = this->renderView();
637 return renderView->compositor()->layerForHorizontalScrollbar();
640 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
642 RenderView* renderView = this->renderView();
645 return renderView->compositor()->layerForVerticalScrollbar();
648 GraphicsLayer* FrameView::layerForScrollCorner() const
650 RenderView* renderView = this->renderView();
653 return renderView->compositor()->layerForScrollCorner();
656 bool FrameView::hasCompositedContent() const
658 if (RenderView* renderView = this->renderView())
659 return renderView->compositor()->inCompositingMode();
663 bool FrameView::isEnclosedInCompositingLayer() const
665 RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
666 if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
669 if (FrameView* parentView = parentFrameView())
670 return parentView->isEnclosedInCompositingLayer();
675 bool FrameView::isSoftwareRenderable() const
677 RenderView* renderView = this->renderView();
678 return !renderView || !renderView->compositor()->has3DContent();
681 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
683 return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
686 inline void FrameView::forceLayoutParentViewIfNeeded()
688 RenderPart* ownerRenderer = m_frame->ownerRenderer();
689 if (!ownerRenderer || !ownerRenderer->frame())
692 RenderBox* contentBox = embeddedContentBox();
696 RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
697 if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
700 // If the embedded SVG document appears the first time, the ownerRenderer has already finished
701 // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
702 // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
703 // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
704 // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
705 // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
706 // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
707 RefPtr<FrameView> frameView = ownerRenderer->frame()->view();
709 // Mark the owner renderer as needing layout.
710 ownerRenderer->setNeedsLayoutAndPrefWidthsRecalc();
712 // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
717 void FrameView::performPreLayoutTasks()
719 TRACE_EVENT0("webkit", "FrameView::performPreLayoutTasks");
720 lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
722 // Don't schedule more layouts, we're in one.
723 TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
725 if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
726 // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
727 m_inSynchronousPostLayout = true;
728 performPostLayoutTasks();
729 m_inSynchronousPostLayout = false;
732 Document* document = m_frame->document();
733 document->notifyResizeForViewportUnits();
735 // Viewport-dependent media queries may cause us to need completely different style information.
736 if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) {
737 document->styleResolverChanged(RecalcStyleDeferred);
738 document->mediaQueryAffectingValueChanged();
740 // FIXME: This instrumentation event is not strictly accurate since cached media query results
741 // do not persist across StyleResolver rebuilds.
742 InspectorInstrumentation::mediaQueryResultChanged(document);
744 document->evaluateMediaQueryList();
747 // Always ensure our style info is up-to-date. This can happen in situations where
748 // the layout beats any sort of style recalc update that needs to occur.
749 TemporaryChange<bool> changeDoingPreLayoutStyleUpdate(m_doingPreLayoutStyleUpdate, true);
750 document->updateStyleIfNeeded();
751 lifecycle().advanceTo(DocumentLifecycle::StyleClean);
754 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
756 TRACE_EVENT0("webkit", "FrameView::performLayout");
758 ASSERT(!isInPerformLayout());
759 lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
761 TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
763 // performLayout is the actual guts of layout().
764 // FIXME: The 300 other lines in layout() probably belong in other helper functions
765 // so that a single human could understand what layout() is actually doing.
768 bool disableLayoutState = false;
769 if (inSubtreeLayout) {
770 RenderView* view = rootForThisLayout->view();
771 disableLayoutState = view->shouldDisableLayoutStateForSubtree(rootForThisLayout);
772 view->pushLayoutState(rootForThisLayout);
774 LayoutStateDisabler layoutStateDisabler(disableLayoutState ? rootForThisLayout->view() : 0);
776 forceLayoutParentViewIfNeeded();
778 // Text Autosizing requires two-pass layout which is incompatible with partial layout.
779 // If enabled, only do partial layout for the second layout.
780 // FIXME (crbug.com/256657): Do not do two layouts for text autosizing.
781 PartialLayoutDisabler partialLayoutDisabler(partialLayout(), m_frame->settings() && m_frame->settings()->textAutosizingEnabled());
782 rootForThisLayout->layout();
783 gatherDebugLayoutRects(rootForThisLayout);
785 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
788 TextAutosizer* textAutosizer = frame().document()->textAutosizer();
789 bool autosized = textAutosizer && textAutosizer->processSubtree(rootForThisLayout);
790 if (autosized && rootForThisLayout->needsLayout()) {
791 TRACE_EVENT0("webkit", "2nd layout due to Text Autosizing");
792 rootForThisLayout->layout();
793 gatherDebugLayoutRects(rootForThisLayout);
797 rootForThisLayout->view()->popLayoutState(rootForThisLayout);
799 lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
802 void FrameView::scheduleOrPerformPostLayoutTasks()
804 if (m_postLayoutTasksTimer.isActive())
807 // Partial layouts should not happen with synchronous post layouts.
808 ASSERT(!(m_inSynchronousPostLayout && partialLayout().isStopping()));
810 if (!m_inSynchronousPostLayout) {
811 m_inSynchronousPostLayout = true;
812 // Calls resumeScheduledEvents()
813 performPostLayoutTasks();
814 m_inSynchronousPostLayout = false;
817 if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
818 // If we need layout or are already in a synchronous call to postLayoutTasks(),
819 // defer widget updates and event dispatch until after we return. postLayoutTasks()
820 // can make us need to update again, and we can get stuck in a nasty cycle unless
821 // we call it through the timer here.
822 m_postLayoutTasksTimer.startOneShot(0);
823 if (!partialLayout().isStopping() && needsLayout())
828 void FrameView::layout(bool allowSubtree)
830 // We should never layout a Document which is not in a Frame.
832 ASSERT(m_frame->view() == this);
833 ASSERT(m_frame->page());
835 if (isInPerformLayout() || !m_frame->document()->isActive())
838 ASSERT(!partialLayout().isStopping());
840 TRACE_EVENT0("webkit", "FrameView::layout");
841 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "Layout");
843 // Protect the view from being deleted during layout (in recalcStyle)
844 RefPtr<FrameView> protector(this);
846 // Every scroll that happens during layout is programmatic.
847 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
849 m_hasPendingLayout = false;
850 DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
852 RELEASE_ASSERT(!isPainting());
854 // Store the current maximal outline size to use when computing the old/new
855 // outline rects for repainting.
856 renderView()->setOldMaximalOutlineSize(renderView()->maximalOutlineSize());
858 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
860 if (!allowSubtree && isSubtreeLayout()) {
861 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
862 m_layoutSubtreeRoot = 0;
865 performPreLayoutTasks();
867 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
868 // so there's no point to continuing to layout
869 if (protector->hasOneRef())
872 Document* document = m_frame->document();
873 bool inSubtreeLayout = isSubtreeLayout();
874 RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderer();
875 if (!rootForThisLayout) {
876 // FIXME: Do we need to set m_size here?
877 ASSERT_NOT_REACHED();
881 bool isPartialLayout = partialLayout().isPartialLayout();
884 lifecycleScope.setFinalState(DocumentLifecycle::StyleClean);
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 (body->hasTagName(framesetTag)) {
898 body->renderer()->setChildNeedsLayout();
899 } else if (body->hasTagName(bodyTag)) {
900 if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport())
901 body->renderer()->setChildNeedsLayout();
910 calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode);
912 shouldDoFullLayout = !inSubtreeLayout && !isPartialLayout && (m_firstLayout || toRenderView(rootForThisLayout)->document().printing());
914 if (!inSubtreeLayout && !isPartialLayout) {
915 // Now set our scrollbar state for the layout.
916 ScrollbarMode currentHMode = horizontalScrollbarMode();
917 ScrollbarMode currentVMode = verticalScrollbarMode();
919 if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
921 setScrollbarsSuppressed(true);
923 m_firstLayout = false;
924 m_firstLayoutCallbackPending = true;
925 m_lastViewportSize = layoutSize(IncludeScrollbars);
926 m_lastZoomFactor = rootForThisLayout->style()->zoom();
928 // Set the initial vMode to AlwaysOn if we're auto.
929 if (vMode == ScrollbarAuto)
930 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
931 // Set the initial hMode to AlwaysOff if we're auto.
932 if (hMode == ScrollbarAuto)
933 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
935 setScrollbarModes(hMode, vMode);
936 setScrollbarsSuppressed(false, true);
938 setScrollbarModes(hMode, vMode);
941 LayoutSize oldSize = m_size;
943 m_size = LayoutSize(layoutSize().width(), layoutSize().height());
945 if (oldSize != m_size) {
946 shouldDoFullLayout = true;
947 if (!m_firstLayout) {
948 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
949 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
950 if (bodyRenderer && bodyRenderer->stretchesToViewport())
951 bodyRenderer->setChildNeedsLayout();
952 else if (rootRenderer && rootRenderer->stretchesToViewport())
953 rootRenderer->setChildNeedsLayout();
958 layer = rootForThisLayout->enclosingLayer();
960 // We need to set m_doFullRepaint before triggering layout as RenderObject::checkForRepaint
961 // checks the boolean to disable local repaints.
962 m_doFullRepaint |= shouldDoFullLayout;
964 performLayout(rootForThisLayout, inSubtreeLayout);
966 m_layoutSubtreeRoot = 0;
967 } // Reset m_layoutSchedulingEnabled to its previous value.
969 if (!inSubtreeLayout && !isPartialLayout && !toRenderView(rootForThisLayout)->document().printing())
972 layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, inSubtreeLayout, m_doFullRepaint));
974 updateCompositingLayersAfterLayout();
978 if (AXObjectCache* cache = rootForThisLayout->document().existingAXObjectCache())
979 cache->postNotification(rootForThisLayout, AXObjectCache::AXLayoutComplete, true);
980 updateAnnotatedRegions();
982 ASSERT(partialLayout().isStopping() || !rootForThisLayout->needsLayout());
984 updateCanBlitOnScrollRecursively();
986 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
987 updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
989 scheduleOrPerformPostLayoutTasks();
991 InspectorInstrumentation::didLayout(cookie, rootForThisLayout);
993 m_nestedLayoutCount--;
994 if (m_nestedLayoutCount)
997 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
999 renderView()->setShouldDoFullRepaintAfterLayout(true);
1001 if (m_doFullRepaint || !partialLayout().isStopping())
1002 repaintTree(rootForThisLayout);
1004 } else if (m_doFullRepaint) {
1005 // FIXME: This isn't really right, since the RenderView doesn't fully encompass
1006 // the visibleContentRect(). It just happens to work out most of the time,
1007 // since first layouts and printing don't have you scrolled anywhere.
1008 renderView()->repaint();
1011 m_doFullRepaint = false;
1013 if (partialLayout().isStopping())
1017 // Post-layout assert that nobody was re-marked as needing layout during layout.
1018 document->renderer()->assertSubtreeIsLaidOut();
1021 // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
1022 // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
1023 // in Frame/Page will fire. One of the post-layout tasks is disconnecting the Frame from
1024 // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
1025 // necessitating this check here.
1026 // ASSERT(frame()->page());
1028 frame().page()->chrome().client().layoutUpdated(m_frame.get());
1031 // The plan is to move to compositor-queried repainting, in which case this
1032 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
1033 // let the compositor pick which to actually draw.
1034 // See http://crbug.com/306706
1035 void FrameView::repaintTree(RenderObject* root)
1037 ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled());
1038 ASSERT(!root->needsLayout());
1039 // We should only repaint for the outer most layout. This works as
1040 // we continue to track repaint rects until this function is called.
1041 ASSERT(!m_nestedLayoutCount);
1043 // FIXME: really, we're in the repaint phase here, and the compositing queries are legal.
1044 // Until those states are fully fledged, I'll just disable the ASSERTS.
1045 DisableCompositingQueryAsserts disabler;
1047 for (RenderObject* renderer = root; renderer; renderer = renderer->nextInPreOrder()) {
1048 // The repaint rectangles stored on the RenderObjects should all match
1049 // the current repaint rectangles for the renderers.
1050 ASSERT(renderer->clippedOverflowRectForRepaint(renderer->containerForRepaint()) == renderer->newRepaintRect());
1052 const LayoutRect& oldRepaintRect = renderer->oldRepaintRect();
1053 const LayoutRect& newRepaintRect = renderer->newRepaintRect();
1055 LayoutRect oldOutlineRect = oldRepaintRect;
1056 oldOutlineRect.inflate(renderView()->oldMaximalOutlineSize());
1058 LayoutRect newOutlineRect = newRepaintRect;
1059 newOutlineRect.inflate(renderView()->maximalOutlineSize());
1061 // FIXME: Currently renderers with layers will get repainted when we call updateLayerPositionsAfterLayout.
1062 // That call should be broken apart to position the layers be done before
1063 // the repaintTree call so this will repaint everything.
1064 bool didFullRepaint = false;
1065 if (!renderer->hasLayer()) {
1066 if (!renderer->layoutDidGetCalled()) {
1067 if (renderer->shouldDoFullRepaintAfterLayout()) {
1068 renderer->repaint();
1069 didFullRepaint = true;
1073 didFullRepaint = renderer->repaintAfterLayoutIfNeeded(renderer->containerForRepaint(),
1074 renderer->shouldDoFullRepaintAfterLayout(), oldRepaintRect, oldOutlineRect,
1075 &newRepaintRect, &newOutlineRect);
1079 if (!didFullRepaint && renderer->shouldRepaintOverflowIfNeeded())
1080 renderer->repaintOverflow();
1082 // Repaint any scrollbars if there is a scrollable area for this renderer.
1083 if (renderer->enclosingLayer()) {
1084 if (RenderLayerScrollableArea* area = renderer->enclosingLayer()->scrollableArea()) {
1085 if (area->hasVerticalBarDamage())
1086 renderer->repaintRectangle(area->verticalBarDamage());
1087 if (area->hasHorizontalBarDamage())
1088 renderer->repaintRectangle(area->horizontalBarDamage());
1089 area->resetScrollbarDamage();
1092 // The list box has a verticalScrollbar we may need to repaint.
1093 if (renderer->isListBox()) {
1094 RenderListBox* listBox = static_cast<RenderListBox*>(renderer);
1095 listBox->repaintScrollbarIfNeeded();
1098 renderer->clearRepaintRects();
1100 renderView()->setOldMaximalOutlineSize(0);
1102 // Repaint the frameviews scrollbars if needed
1103 if (hasVerticalBarDamage())
1104 invalidateRect(verticalBarDamage());
1105 if (hasHorizontalBarDamage())
1106 invalidateRect(horizontalBarDamage());
1107 resetScrollbarDamage();
1110 DocumentLifecycle& FrameView::lifecycle() const
1112 return m_frame->document()->lifecycle();
1115 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot)
1118 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
1121 if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
1123 GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
1127 GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
1129 debugInfo.currentLayoutRects().clear();
1130 for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
1131 if (renderer->layoutDidGetCalled()) {
1132 FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->newRepaintRect()));
1133 LayoutRect rect = quad.enclosingBoundingBox();
1134 debugInfo.currentLayoutRects().append(rect);
1135 renderer->setLayoutDidGetCalled(false);
1140 RenderBox* FrameView::embeddedContentBox() const
1142 RenderView* renderView = this->renderView();
1146 RenderObject* firstChild = renderView->firstChild();
1147 if (!firstChild || !firstChild->isBox())
1150 // Curently only embedded SVG documents participate in the size-negotiation logic.
1151 if (firstChild->isSVGRoot())
1152 return toRenderBox(firstChild);
1158 void FrameView::addWidget(RenderWidget* object)
1160 m_widgets.add(object);
1163 void FrameView::removeWidget(RenderWidget* object)
1165 m_widgets.remove(object);
1168 void FrameView::updateWidgetPositions()
1170 Vector<RefPtr<RenderWidget> > widgets;
1171 copyToVector(m_widgets, widgets);
1173 // Script or plugins could detach the frame so abort processing if that happens.
1175 for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1176 widgets[i]->updateWidgetPosition();
1178 for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1179 widgets[i]->widgetPositionsUpdated();
1182 void FrameView::addWidgetToUpdate(RenderEmbeddedObject& object)
1184 // Tell the DOM element that it needs a widget update.
1185 Node* node = object.node();
1186 if (node->hasTagName(objectTag) || node->hasTagName(embedTag))
1187 toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1189 m_widgetUpdateSet.add(&object);
1192 void FrameView::setMediaType(const AtomicString& mediaType)
1194 ASSERT(m_frame->document());
1195 m_frame->document()->mediaQueryAffectingValueChanged();
1196 m_mediaType = mediaType;
1199 AtomicString FrameView::mediaType() const
1201 // See if we have an override type.
1202 String overrideType;
1203 InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType);
1204 if (!overrideType.isNull())
1205 return AtomicString(overrideType);
1209 void FrameView::adjustMediaTypeForPrinting(bool printing)
1212 if (m_mediaTypeWhenNotPrinting.isNull())
1213 m_mediaTypeWhenNotPrinting = mediaType();
1214 setMediaType("print");
1216 if (!m_mediaTypeWhenNotPrinting.isNull())
1217 setMediaType(m_mediaTypeWhenNotPrinting);
1218 m_mediaTypeWhenNotPrinting = nullAtom;
1222 bool FrameView::useSlowRepaints(bool considerOverlap) const
1224 bool mustBeSlow = m_slowRepaintObjectCount > 0;
1226 if (contentsInCompositedLayer())
1229 // The chromium compositor does not support scrolling a non-composited frame within a composited page through
1230 // the fast scrolling path, so force slow scrolling in that case.
1231 if (m_frame->ownerElement() && !hasCompositedContent() && m_frame->page() && m_frame->page()->mainFrame()->view()->hasCompositedContent())
1234 bool isOverlapped = m_isOverlapped && considerOverlap;
1236 if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque)
1239 if (FrameView* parentView = parentFrameView())
1240 return parentView->useSlowRepaints(considerOverlap);
1245 bool FrameView::useSlowRepaintsIfNotOverlapped() const
1247 return useSlowRepaints(false);
1250 void FrameView::updateCanBlitOnScrollRecursively()
1252 // FIXME: useSlowRepaints reads compositing state in nested frames. Compositing state on the nested
1253 // frames is not necessarily up to date.
1254 // https://code.google.com/p/chromium/issues/detail?id=343766
1255 DisableCompositingQueryAsserts disabler;
1257 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1258 if (FrameView* view = frame->view())
1259 view->setCanBlitOnScroll(!view->useSlowRepaints());
1263 bool FrameView::contentsInCompositedLayer() const
1265 RenderView* renderView = this->renderView();
1266 if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) {
1267 GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer();
1268 if (layer && layer->drawsContent())
1275 void FrameView::setCannotBlitToWindow()
1277 m_cannotBlitToWindow = true;
1278 updateCanBlitOnScrollRecursively();
1281 void FrameView::addSlowRepaintObject()
1283 if (!m_slowRepaintObjectCount++) {
1284 updateCanBlitOnScrollRecursively();
1286 if (Page* page = m_frame->page()) {
1287 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1288 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1293 void FrameView::removeSlowRepaintObject()
1295 ASSERT(m_slowRepaintObjectCount > 0);
1296 m_slowRepaintObjectCount--;
1297 if (!m_slowRepaintObjectCount) {
1298 updateCanBlitOnScrollRecursively();
1300 if (Page* page = m_frame->page()) {
1301 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1302 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1307 void FrameView::addViewportConstrainedObject(RenderObject* object)
1309 if (!m_viewportConstrainedObjects)
1310 m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1312 if (!m_viewportConstrainedObjects->contains(object)) {
1313 m_viewportConstrainedObjects->add(object);
1315 if (Page* page = m_frame->page()) {
1316 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1317 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1322 void FrameView::removeViewportConstrainedObject(RenderObject* object)
1324 if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1325 m_viewportConstrainedObjects->remove(object);
1326 if (Page* page = m_frame->page()) {
1327 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1328 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1331 // FIXME: In addFixedObject() we only call this if there's a platform widget,
1332 // why isn't the same check being made here?
1333 updateCanBlitOnScrollRecursively();
1337 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1339 LayoutRect viewportRect = visibleContentRect();
1340 // Ignore overhang. No-op when not using rubber banding.
1341 viewportRect.setLocation(clampScrollPosition(scrollPosition()));
1342 return viewportRect;
1345 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged)
1347 // If viewport is not enabled, frameRect change will cause layout size change and then layout.
1348 // Otherwise, viewport constrained objects need their layout flags set separately to ensure
1349 // they are positioned correctly.
1350 if ((m_frame->settings() && !m_frame->settings()->viewportEnabled()) || !hasViewportConstrainedObjects())
1353 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1354 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1355 RenderObject* renderer = *it;
1356 RenderStyle* style = renderer->style();
1358 if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto()))
1359 renderer->setNeedsPositionedMovementLayout();
1361 renderer->setNeedsLayout();
1363 if (heightChanged) {
1364 if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto()))
1365 renderer->setNeedsPositionedMovementLayout();
1367 renderer->setNeedsLayout();
1372 IntSize FrameView::scrollOffsetForFixedPosition() const
1374 return toIntSize(clampScrollPosition(scrollPosition()));
1377 IntPoint FrameView::lastKnownMousePosition() const
1379 return m_frame->eventHandler().lastKnownMousePosition();
1382 bool FrameView::shouldSetCursor() const
1384 Page* page = frame().page();
1385 return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive();
1388 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
1390 if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1391 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1395 // https://code.google.com/p/chromium/issues/detail?id=343767
1396 DisableCompositingQueryAsserts disabler;
1397 const bool isCompositedContentLayer = contentsInCompositedLayer();
1399 // Get the rects of the fixed objects visible in the rectToScroll
1400 Region regionToUpdate;
1401 ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1402 for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1403 RenderObject* renderer = *it;
1404 if (!renderer->style()->hasViewportConstrainedPosition())
1407 // Fixed items should always have layers.
1408 ASSERT(renderer->hasLayer());
1409 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1411 // Layers that paint into their ancestor or into a grouped backing will still need
1412 // to apply a repaint invalidation. If the layer paints into its own backing, then
1413 // it does not need repainting just to scroll.
1414 if (layer->compositingState() == PaintsIntoOwnBacking)
1417 if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView
1418 || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) {
1419 // Don't invalidate for invisible fixed layers.
1423 if (layer->hasAncestorWithFilterOutsets()) {
1424 // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1425 // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1429 IntRect updateRect = pixelSnappedIntRect(layer->repainter().repaintRectIncludingNonCompositingDescendants());
1431 RenderLayer* enclosingCompositingLayer = layer->enclosingCompositingLayer(ExcludeSelf);
1432 if (enclosingCompositingLayer && !enclosingCompositingLayer->renderer()->isRenderView()) {
1433 // If the fixed-position layer is contained by a composited layer that is not its containing block,
1434 // then we have to invlidate that enclosing layer, not the RenderView.
1435 updateRect.moveBy(scrollPosition());
1436 IntRect previousRect = updateRect;
1437 previousRect.move(scrollDelta);
1438 updateRect.unite(previousRect);
1439 enclosingCompositingLayer->repainter().setBackingNeedsRepaintInRect(updateRect);
1441 // Coalesce the repaints that will be issued to the renderView.
1442 updateRect = contentsToRootView(updateRect);
1443 if (!isCompositedContentLayer && clipsRepaints())
1444 updateRect.intersect(rectToScroll);
1445 if (!updateRect.isEmpty())
1446 regionToUpdate.unite(updateRect);
1451 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
1453 // 2) update the area of fixed objects that has been invalidated
1454 Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1455 size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1456 for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1457 IntRect updateRect = subRectsToUpdate[i];
1458 IntRect scrolledRect = updateRect;
1459 scrolledRect.move(scrollDelta);
1460 updateRect.unite(scrolledRect);
1461 if (isCompositedContentLayer) {
1462 updateRect = rootViewToContents(updateRect);
1463 ASSERT(renderView());
1464 renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect);
1467 if (clipsRepaints())
1468 updateRect.intersect(rectToScroll);
1469 hostWindow()->invalidateContentsAndRootView(updateRect);
1475 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1477 // FIXME: This is called when JS calls scrollTo, at which point there's no guarantee that
1478 // compositing state is up to date.
1479 // https://code.google.com/p/chromium/issues/detail?id=343767
1480 DisableCompositingQueryAsserts disabler;
1482 if (contentsInCompositedLayer()) {
1483 IntRect updateRect = visibleContentRect();
1484 ASSERT(renderView());
1485 renderView()->layer()->repainter().setBackingNeedsRepaintInRect(updateRect);
1487 if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
1488 if (isEnclosedInCompositingLayer()) {
1489 LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1490 frameRenderer->borderTop() + frameRenderer->paddingTop(),
1491 visibleWidth(), visibleHeight());
1492 frameRenderer->repaintRectangle(rect);
1497 ScrollView::scrollContentsSlowPath(updateRect);
1500 // Note that this gets called at painting time.
1501 void FrameView::setIsOverlapped(bool isOverlapped)
1503 if (isOverlapped == m_isOverlapped)
1506 m_isOverlapped = isOverlapped;
1507 updateCanBlitOnScrollRecursively();
1510 void FrameView::setContentIsOpaque(bool contentIsOpaque)
1512 if (contentIsOpaque == m_contentIsOpaque)
1515 m_contentIsOpaque = contentIsOpaque;
1516 updateCanBlitOnScrollRecursively();
1519 void FrameView::restoreScrollbar()
1521 setScrollbarsSuppressed(false);
1524 bool FrameView::scrollToFragment(const KURL& url)
1526 // If our URL has no ref, then we have no place we need to jump to.
1527 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1528 // and possibly repaint because :target pseudo class may have been
1529 // set (see bug 11321).
1530 if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1533 String fragmentIdentifier = url.fragmentIdentifier();
1534 if (scrollToAnchor(fragmentIdentifier))
1537 // Try again after decoding the ref, based on the document's encoding.
1538 if (m_frame->document()->encoding().isValid())
1539 return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()));
1544 bool FrameView::scrollToAnchor(const String& name)
1546 ASSERT(m_frame->document());
1548 if (!m_frame->document()->haveStylesheetsLoaded()) {
1549 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1553 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1555 Element* anchorNode = m_frame->document()->findAnchor(name);
1557 // Setting to null will clear the current target.
1558 m_frame->document()->setCSSTarget(anchorNode);
1560 if (m_frame->document()->isSVGDocument()) {
1561 if (SVGSVGElement* svg = toSVGDocument(m_frame->document())->rootElement()) {
1562 svg->setupInitialView(name, anchorNode);
1568 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1569 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1572 maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1574 // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1575 if (anchorNode && anchorNode->isFocusable())
1576 m_frame->document()->setFocusedElement(anchorNode);
1581 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1583 m_maintainScrollPositionAnchor = anchorNode;
1584 if (!m_maintainScrollPositionAnchor)
1587 // We need to update the layout before scrolling, otherwise we could
1588 // really mess things up if an anchor scroll comes at a bad moment.
1589 m_frame->document()->updateStyleIfNeeded();
1590 // Only do a layout if changes have occurred that make it necessary.
1591 RenderView* renderView = this->renderView();
1592 if (renderView && renderView->needsLayout())
1598 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1600 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1602 LayoutRect bounds = element->boundingBox();
1603 int centeringOffsetX = (rect.width() - bounds.width()) / 2;
1604 int centeringOffsetY = (rect.height() - bounds.height()) / 2;
1605 setScrollPosition(IntPoint(bounds.x() - centeringOffsetX - rect.x(), bounds.y() - centeringOffsetY - rect.y()));
1608 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
1610 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1611 m_maintainScrollPositionAnchor = 0;
1613 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1615 if (newScrollPosition == scrollPosition())
1618 ScrollView::setScrollPosition(newScrollPosition);
1621 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint)
1623 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1625 if (newScrollPosition == scrollPosition())
1628 TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false);
1629 notifyScrollPositionChanged(newScrollPosition);
1632 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1634 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1637 void FrameView::setLayoutSize(const IntSize& size)
1639 ASSERT(!layoutSizeFixedToFrameSize());
1641 setLayoutSizeInternal(size);
1644 void FrameView::scrollPositionChanged()
1646 setWasScrolledByUser(true);
1648 Document* document = m_frame->document();
1649 document->enqueueScrollEventForNode(document);
1651 m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1653 if (RenderView* renderView = document->renderView()) {
1654 if (renderView->usesCompositing()) {
1655 // https://code.google.com/p/chromium/issues/detail?id=343767
1656 DisableCompositingQueryAsserts disabler;
1657 renderView->compositor()->frameViewDidScroll();
1661 if (m_didScrollTimer.isActive())
1662 m_didScrollTimer.stop();
1663 m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll);
1666 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1668 if (m_frame->document() && m_frame->document()->renderer()) {
1669 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1673 void FrameView::repaintFixedElementsAfterScrolling()
1675 RefPtr<FrameView> protect(this);
1676 // For fixed position elements, update widget positions and compositing layers after scrolling,
1677 // but only if we're not inside of layout.
1678 if (!m_nestedLayoutCount && hasViewportConstrainedObjects()) {
1679 updateWidgetPositions();
1680 if (RenderView* renderView = this->renderView())
1681 renderView->layer()->updateLayerPositionsAfterDocumentScroll();
1685 void FrameView::updateFixedElementsAfterScrolling()
1687 if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
1688 if (RenderView* renderView = this->renderView())
1689 renderView->compositor()->setNeedsCompositingUpdate(CompositingUpdateOnScroll);
1693 bool FrameView::shouldRubberBandInDirection(ScrollDirection direction) const
1695 Page* page = frame().page();
1697 return ScrollView::shouldRubberBandInDirection(direction);
1698 return page->chrome().client().shouldRubberBandInDirection(direction);
1701 bool FrameView::isRubberBandInProgress() const
1703 if (scrollbarsSuppressed())
1706 // If the main thread updates the scroll position for this FrameView, we should return
1707 // ScrollAnimator::isRubberBandInProgress().
1708 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1709 return scrollAnimator->isRubberBandInProgress();
1714 HostWindow* FrameView::hostWindow() const
1716 Page* page = frame().page();
1719 return &page->chrome();
1722 void FrameView::repaintContentRectangle(const IntRect& r)
1724 ASSERT(repaintAllowed());
1725 ASSERT(!m_frame->ownerElement());
1727 if (m_isTrackingRepaints) {
1728 IntRect repaintRect = r;
1729 repaintRect.move(-scrollOffset());
1730 m_trackedRepaintRects.append(repaintRect);
1733 ScrollView::repaintContentRectangle(r);
1736 void FrameView::contentsResized()
1738 ScrollView::contentsResized();
1742 void FrameView::scrollbarExistenceDidChange()
1744 // We check to make sure the view is attached to a frame() as this method can
1745 // be triggered before the view is attached by Frame::createView(...) setting
1746 // various values such as setScrollBarModes(...) for example. An ASSERT is
1747 // triggered when a view is layout before being attached to a frame().
1748 if (!frame().view())
1751 // Note that simply having overlay scrollbars is not sufficient to be
1752 // certain that scrollbars' presence does not impact layout. This should
1753 // also check if custom scrollbars (as reported by shouldUseCustomScrollbars)
1754 // are in use as well.
1755 // http://crbug.com/269692
1756 bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars();
1758 if (!useOverlayScrollbars && needsLayout())
1761 // FIXME: Rather than updating this state synchronously, we should set some dirty bits
1762 // and clean them out when updating compositing.
1763 // https://code.google.com/p/chromium/issues/detail?id=343756
1764 DisableCompositingQueryAsserts disabler;
1765 if (renderView() && renderView()->usesCompositing()) {
1766 renderView()->compositor()->frameViewScrollbarsExistenceDidChange();
1768 if (!useOverlayScrollbars)
1769 renderView()->compositor()->frameViewDidChangeSize();
1773 void FrameView::handleLoadCompleted()
1775 // Once loading has completed, allow autoSize one last opportunity to
1776 // reduce the size of the frame.
1777 autoSizeIfEnabled();
1780 void FrameView::scheduleRelayout()
1782 ASSERT(m_frame->view() == this);
1784 if (isSubtreeLayout()) {
1785 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1786 m_layoutSubtreeRoot = 0;
1788 if (!m_layoutSchedulingEnabled)
1792 if (!m_frame->document()->shouldScheduleLayout())
1794 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1796 if (m_hasPendingLayout)
1798 m_hasPendingLayout = true;
1799 if (!isServicingAnimations())
1800 scheduleAnimation();
1803 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1805 for (RenderObject* r = descendant; r; r = r->container()) {
1812 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1814 ASSERT(m_frame->view() == this);
1816 RenderView* renderView = this->renderView();
1817 if (renderView && renderView->needsLayout()) {
1819 relayoutRoot->markContainingBlocksForLayout(false);
1823 if (layoutPending() || !m_layoutSchedulingEnabled) {
1824 if (m_layoutSubtreeRoot != relayoutRoot) {
1825 if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
1826 // Keep the current root
1827 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
1828 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1829 } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
1830 // Re-root at relayoutRoot
1831 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
1832 m_layoutSubtreeRoot = relayoutRoot;
1833 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1834 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1836 // Just do a full relayout
1837 if (isSubtreeLayout())
1838 m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1839 m_layoutSubtreeRoot = 0;
1840 relayoutRoot->markContainingBlocksForLayout(false);
1841 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1844 } else if (m_layoutSchedulingEnabled) {
1845 m_layoutSubtreeRoot = relayoutRoot;
1846 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1847 InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1848 m_hasPendingLayout = true;
1849 if (!isServicingAnimations())
1850 scheduleAnimation();
1854 bool FrameView::layoutPending() const
1856 return m_hasPendingLayout;
1859 bool FrameView::isInPerformLayout() const
1861 ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1862 return m_inPerformLayout;
1865 bool FrameView::needsLayout() const
1867 // This can return true in cases where the document does not have a body yet.
1868 // Document::shouldScheduleLayout takes care of preventing us from scheduling
1869 // layout in that case.
1871 RenderView* renderView = this->renderView();
1872 return layoutPending()
1873 || (renderView && renderView->needsLayout())
1874 || isSubtreeLayout();
1877 void FrameView::setNeedsLayout()
1879 if (RenderView* renderView = this->renderView())
1880 renderView->setNeedsLayout();
1883 void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
1885 TemporaryChange<bool> servicing(m_servicingAnimations, true);
1887 for (RefPtr<Frame> frame = m_frame; frame; frame = frame->tree().traverseNext()) {
1888 frame->view()->serviceScrollAnimations();
1889 DocumentAnimations::serviceOnAnimationFrame(*frame->document(), monotonicAnimationStartTime);
1892 Vector<RefPtr<Document> > documents;
1893 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext())
1894 documents.append(frame->document());
1896 for (size_t i = 0; i < documents.size(); ++i)
1897 documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
1900 bool FrameView::isTransparent() const
1902 return m_isTransparent;
1905 void FrameView::setTransparent(bool isTransparent)
1907 m_isTransparent = isTransparent;
1908 if (renderView() && renderView()->layer()->hasCompositedLayerMapping())
1909 renderView()->layer()->compositedLayerMapping()->updateContentsOpaque();
1912 bool FrameView::hasOpaqueBackground() const
1914 return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1917 Color FrameView::baseBackgroundColor() const
1919 return m_baseBackgroundColor;
1922 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1924 m_baseBackgroundColor = backgroundColor;
1926 if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) {
1927 CompositedLayerMappingPtr compositedLayerMapping = renderView()->layer()->compositedLayerMapping();
1928 compositedLayerMapping->updateContentsOpaque();
1929 if (compositedLayerMapping->mainGraphicsLayer())
1930 compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1932 recalculateScrollbarOverlayStyle();
1935 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1937 for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1938 if (FrameView* view = frame->view()) {
1939 view->setTransparent(transparent);
1940 view->setBaseBackgroundColor(backgroundColor);
1945 void FrameView::scrollToAnchor()
1947 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1951 if (!anchorNode->renderer())
1955 if (anchorNode != m_frame->document())
1956 rect = anchorNode->boundingBox();
1958 // Scroll nested layers and frames to reveal the anchor.
1959 // Align to the top and to the closest side (this matches other browsers).
1960 anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1962 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1963 cache->handleScrolledToAnchor(anchorNode.get());
1965 // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
1966 m_maintainScrollPositionAnchor = anchorNode;
1969 bool FrameView::updateWidgets()
1971 if (m_nestedLayoutCount > 1 || m_widgetUpdateSet.isEmpty())
1974 // Need to swap because script will run inside the below loop and invalidate the iterator.
1975 EmbeddedObjectSet objects;
1976 objects.swap(m_widgetUpdateSet);
1978 for (EmbeddedObjectSet::iterator it = objects.begin(); it != objects.end(); ++it) {
1979 RenderEmbeddedObject& object = **it;
1980 HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
1982 // The object may have already been destroyed (thus node cleared),
1983 // but FrameView holds a manual ref, so it won't have been deleted.
1987 // No need to update if it's already crashed or known to be missing.
1988 if (object.showsUnavailablePluginIndicator())
1991 if (element->needsWidgetUpdate())
1992 element->updateWidget();
1993 object.updateWidgetPosition();
1995 // Prevent plugins from causing infinite updates of themselves.
1996 // FIXME: Do we really need to prevent this?
1997 m_widgetUpdateSet.remove(&object);
2000 return m_widgetUpdateSet.isEmpty();
2003 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
2005 RefPtr<FrameView> protect(this);
2006 m_updateWidgetsTimer.stop();
2007 for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
2008 if (updateWidgets())
2013 void FrameView::flushAnyPendingPostLayoutTasks()
2015 if (m_postLayoutTasksTimer.isActive())
2016 performPostLayoutTasks();
2017 if (m_updateWidgetsTimer.isActive())
2018 updateWidgetsTimerFired(0);
2021 void FrameView::performPostLayoutTasks()
2023 TRACE_EVENT0("webkit", "FrameView::performPostLayoutTasks");
2024 RefPtr<FrameView> protect(this);
2026 m_postLayoutTasksTimer.stop();
2028 m_frame->selection().setCaretRectNeedsUpdate();
2029 m_frame->selection().updateAppearance();
2031 if (m_nestedLayoutCount <= 1) {
2032 if (m_firstLayoutCallbackPending) {
2033 m_firstLayoutCallbackPending = false;
2034 m_frame->loader().didFirstLayout();
2037 // Ensure that we always send this eventually.
2038 if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad())
2039 m_isVisuallyNonEmpty = true;
2041 // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2042 if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2043 m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2044 // FIXME: This callback is probably not needed, but is currently used
2045 // by android for setting the background color.
2046 m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout();
2050 FontFaceSet::didLayout(m_frame->document());
2052 updateWidgetPositions();
2054 // Plugins could have torn down the page inside updateWidgetPositions().
2058 if (!m_updateWidgetsTimer.isActive())
2059 m_updateWidgetsTimer.startOneShot(0);
2061 if (Page* page = m_frame->page()) {
2062 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2063 scrollingCoordinator->notifyLayoutUpdated();
2068 sendResizeEventIfNeeded();
2071 void FrameView::sendResizeEventIfNeeded()
2075 RenderView* renderView = this->renderView();
2076 if (!renderView || renderView->document().printing())
2079 IntSize currentSize = layoutSize(IncludeScrollbars);
2080 float currentZoomFactor = renderView->style()->zoom();
2082 bool shouldSendResizeEvent = currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor;
2084 m_lastViewportSize = currentSize;
2085 m_lastZoomFactor = currentZoomFactor;
2087 if (!shouldSendResizeEvent)
2090 m_frame->document()->enqueueResizeEvent();
2093 InspectorInstrumentation::didResizeMainFrame(m_frame->page());
2096 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2098 performPostLayoutTasks();
2101 void FrameView::updateCounters()
2103 RenderView* view = renderView();
2104 if (!view->hasRenderCounters())
2107 for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) {
2108 if (!renderer->isCounter())
2111 toRenderCounter(renderer)->updateCounter();
2115 void FrameView::autoSizeIfEnabled()
2117 if (!m_shouldAutoSize)
2123 TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
2125 Document* document = frame().document();
2126 if (!document || !document->isActive())
2129 Element* documentElement = document->documentElement();
2130 if (!documentElement)
2133 // If this is the first time we run autosize, start from small height and
2134 // allow it to grow.
2135 if (!m_didRunAutosize)
2136 resize(frameRect().width(), m_minAutoSize.height());
2138 IntSize size = frameRect().size();
2140 // Do the resizing twice. The first time is basically a rough calculation using the preferred width
2141 // which may result in a height change during the second iteration.
2142 for (int i = 0; i < 2; i++) {
2143 // Update various sizes including contentsSize, scrollHeight, etc.
2144 document->updateLayoutIgnorePendingStylesheets();
2146 RenderView* renderView = document->renderView();
2150 int width = renderView->minPreferredLogicalWidth();
2152 RenderBox* documentRenderBox = documentElement->renderBox();
2153 if (!documentRenderBox)
2156 int height = documentRenderBox->scrollHeight();
2157 IntSize newSize(width, height);
2159 // Check to see if a scrollbar is needed for a given dimension and
2160 // if so, increase the other dimension to account for the scrollbar.
2161 // Since the dimensions are only for the view rectangle, once a
2162 // dimension exceeds the maximum, there is no need to increase it further.
2163 if (newSize.width() > m_maxAutoSize.width()) {
2164 RefPtr<Scrollbar> localHorizontalScrollbar = horizontalScrollbar();
2165 if (!localHorizontalScrollbar)
2166 localHorizontalScrollbar = createScrollbar(HorizontalScrollbar);
2167 if (!localHorizontalScrollbar->isOverlayScrollbar())
2168 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
2170 // Don't bother checking for a vertical scrollbar because the width is at
2171 // already greater the maximum.
2172 } else if (newSize.height() > m_maxAutoSize.height()) {
2173 RefPtr<Scrollbar> localVerticalScrollbar = verticalScrollbar();
2174 if (!localVerticalScrollbar)
2175 localVerticalScrollbar = createScrollbar(VerticalScrollbar);
2176 if (!localVerticalScrollbar->isOverlayScrollbar())
2177 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
2179 // Don't bother checking for a horizontal scrollbar because the height is
2180 // already greater the maximum.
2183 // Ensure the size is at least the min bounds.
2184 newSize = newSize.expandedTo(m_minAutoSize);
2186 // Bound the dimensions by the max bounds and determine what scrollbars to show.
2187 ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
2188 if (newSize.width() > m_maxAutoSize.width()) {
2189 newSize.setWidth(m_maxAutoSize.width());
2190 horizonalScrollbarMode = ScrollbarAlwaysOn;
2192 ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
2193 if (newSize.height() > m_maxAutoSize.height()) {
2194 newSize.setHeight(m_maxAutoSize.height());
2195 verticalScrollbarMode = ScrollbarAlwaysOn;
2198 if (newSize == size)
2201 // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
2202 // unless autoresize has just been turned on or the maximum size is smaller than the current size.
2203 if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
2204 && !m_frame->document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width()))
2207 resize(newSize.width(), newSize.height());
2208 // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
2209 // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
2210 setVerticalScrollbarLock(false);
2211 setHorizontalScrollbarLock(false);
2212 setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
2214 m_didRunAutosize = true;
2217 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2219 if (!m_viewportRenderer)
2222 if (m_overflowStatusDirty) {
2223 m_horizontalOverflow = horizontalOverflow;
2224 m_verticalOverflow = verticalOverflow;
2225 m_overflowStatusDirty = false;
2229 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2230 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2232 if (horizontalOverflowChanged || verticalOverflowChanged) {
2233 m_horizontalOverflow = horizontalOverflow;
2234 m_verticalOverflow = verticalOverflow;
2236 RefPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow);
2237 event->setTarget(m_viewportRenderer->node());
2238 m_frame->document()->enqueueAnimationFrameEvent(event.release());
2243 IntRect FrameView::windowClipRect(bool clipToContents) const
2245 ASSERT(m_frame->view() == this);
2247 if (paintsEntireContents())
2248 return IntRect(IntPoint(), contentsSize());
2250 // Set our clip rect to be our contents.
2251 IntRect clipRect = contentsToWindow(visibleContentRect(clipToContents ? ExcludeScrollbars : IncludeScrollbars));
2252 if (!m_frame->ownerElement())
2255 // Take our owner element and get its clip rect.
2256 HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement();
2257 FrameView* parentView = ownerElement->document().view();
2259 clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement, true));
2263 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement, bool clipToLayerContents) const
2265 // The renderer can sometimes be null when style="display:none" interacts
2266 // with external content and plugins.
2267 if (!ownerElement->renderer())
2268 return windowClipRect();
2270 // If we have no layer, just return our window clip rect.
2271 const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2272 if (!enclosingLayer)
2273 return windowClipRect();
2275 // Apply the clip from the layer.
2277 if (clipToLayerContents) {
2278 // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2279 // https://code.google.com/p/chromium/issues/detail?id=343769
2280 DisableCompositingQueryAsserts disabler;
2281 clipRect = pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect());
2283 clipRect = pixelSnappedIntRect(enclosingLayer->clipper().selfClipRect());
2285 clipRect = contentsToWindow(clipRect);
2286 return intersection(clipRect, windowClipRect());
2289 bool FrameView::isActive() const
2291 Page* page = frame().page();
2292 return page && page->focusController().isActive();
2295 void FrameView::scrollTo(const IntSize& newOffset)
2297 LayoutSize offset = scrollOffset();
2298 ScrollView::scrollTo(newOffset);
2299 if (offset != scrollOffset())
2300 scrollPositionChanged();
2301 frame().loader().client()->didChangeScrollOffset();
2304 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2306 // Add in our offset within the FrameView.
2307 IntRect dirtyRect = rect;
2308 dirtyRect.moveBy(scrollbar->location());
2310 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && isInPerformLayout()) {
2311 if (scrollbar == verticalScrollbar()) {
2312 m_verticalBarDamage = dirtyRect;
2313 m_hasVerticalBarDamage = true;
2315 m_horizontalBarDamage = dirtyRect;
2316 m_hasHorizontalBarDamage = true;
2319 invalidateRect(dirtyRect);
2323 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2325 tickmarks = frame().document()->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch);
2328 IntRect FrameView::windowResizerRect() const
2330 Page* page = frame().page();
2333 return page->chrome().windowResizerRect();
2336 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
2338 if (m_visibleContentScaleFactor == visibleContentScaleFactor)
2341 m_visibleContentScaleFactor = visibleContentScaleFactor;
2342 updateScrollbars(scrollOffset());
2345 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2347 m_inputEventsOffsetForEmulation = offset;
2348 m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2351 IntSize FrameView::inputEventsOffsetForEmulation() const
2353 return m_inputEventsOffsetForEmulation;
2356 float FrameView::inputEventsScaleFactor() const
2358 return visibleContentScaleFactor() * m_inputEventsScaleFactorForEmulation;
2361 bool FrameView::scrollbarsCanBeActive() const
2363 if (m_frame->view() != this)
2366 return !!m_frame->document();
2369 ScrollableArea* FrameView::enclosingScrollableArea() const
2371 // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
2375 IntRect FrameView::scrollableAreaBoundingBox() const
2377 RenderPart* ownerRenderer = frame().ownerRenderer();
2381 return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
2384 bool FrameView::isScrollable()
2387 // 1) If there an actual overflow.
2388 // 2) display:none or visibility:hidden set to self or inherited.
2389 // 3) overflow{-x,-y}: hidden;
2390 // 4) scrolling: no;
2393 IntSize contentsSize = this->contentsSize();
2394 IntSize visibleContentSize = visibleContentRect().size();
2395 if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2399 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2400 if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
2404 ScrollbarMode horizontalMode;
2405 ScrollbarMode verticalMode;
2406 calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly);
2407 if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2413 void FrameView::updateScrollableAreaSet()
2415 // That ensures that only inner frames are cached.
2416 FrameView* parentFrameView = this->parentFrameView();
2417 if (!parentFrameView)
2420 if (!isScrollable()) {
2421 parentFrameView->removeScrollableArea(this);
2425 parentFrameView->addScrollableArea(this);
2428 bool FrameView::shouldSuspendScrollAnimations() const
2430 return m_frame->loader().state() != FrameStateComplete;
2433 void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate)
2439 ScrollView::scrollbarStyleChanged(newStyle, forceUpdate);
2442 void FrameView::notifyPageThatContentAreaWillPaint() const
2444 Page* page = m_frame->page();
2448 contentAreaWillPaint();
2450 if (!m_scrollableAreas)
2453 for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) {
2454 ScrollableArea* scrollableArea = *it;
2456 if (!scrollableArea->scrollbarsCanBeActive())
2459 scrollableArea->contentAreaWillPaint();
2463 bool FrameView::scrollAnimatorEnabled() const
2465 if (m_frame->settings())
2466 return m_frame->settings()->scrollAnimatorEnabled();
2470 void FrameView::updateAnnotatedRegions()
2472 Document* document = m_frame->document();
2473 if (!document->hasAnnotatedRegions())
2475 Vector<AnnotatedRegionValue> newRegions;
2476 document->renderBox()->collectAnnotatedRegions(newRegions);
2477 if (newRegions == document->annotatedRegions())
2479 document->setAnnotatedRegions(newRegions);
2480 if (Page* page = m_frame->page())
2481 page->chrome().client().annotatedRegionsChanged();
2484 void FrameView::updateScrollCorner()
2486 RefPtr<RenderStyle> cornerStyle;
2487 IntRect cornerRect = scrollCornerRect();
2488 Document* doc = m_frame->document();
2490 if (doc && !cornerRect.isEmpty()) {
2491 // Try the <body> element first as a scroll corner source.
2492 if (Element* body = doc->body()) {
2493 if (RenderObject* renderer = body->renderer())
2494 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2498 // If the <body> didn't have a custom style, then the root element might.
2499 if (Element* docElement = doc->documentElement()) {
2500 if (RenderObject* renderer = docElement->renderer())
2501 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2506 // If we have an owning ipage/Frame element, then it can set the custom scrollbar also.
2507 if (RenderPart* renderer = m_frame->ownerRenderer())
2508 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2513 if (!m_scrollCorner)
2514 m_scrollCorner = RenderScrollbarPart::createAnonymous(doc);
2515 m_scrollCorner->setStyle(cornerStyle.release());
2516 invalidateScrollCorner(cornerRect);
2517 } else if (m_scrollCorner) {
2518 m_scrollCorner->destroy();
2522 ScrollView::updateScrollCorner();
2525 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
2527 if (context->updatingControlTints()) {
2528 updateScrollCorner();
2532 if (m_scrollCorner) {
2533 bool needsBackgorund = isMainFrame();
2534 if (needsBackgorund)
2535 context->fillRect(cornerRect, baseBackgroundColor());
2536 m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
2540 ScrollView::paintScrollCorner(context, cornerRect);
2543 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
2545 bool needsBackgorund = bar->isCustomScrollbar() && isMainFrame();
2546 if (needsBackgorund) {
2547 IntRect toFill = bar->frameRect();
2548 toFill.intersect(rect);
2549 context->fillRect(toFill, baseBackgroundColor());
2552 ScrollView::paintScrollbar(context, bar, rect);
2555 Color FrameView::documentBackgroundColor() const
2557 // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2558 // the document and the body against the base background color of the frame view.
2559 // Background images are unfortunately impractical to include.
2561 Color result = baseBackgroundColor();
2562 if (!frame().document())
2565 Element* htmlElement = frame().document()->documentElement();
2566 Element* bodyElement = frame().document()->body();
2568 // We take the aggregate of the base background color
2569 // the <html> background color, and the <body>
2570 // background color to find the document color. The
2571 // addition of the base background color is not
2572 // technically part of the document background, but it
2573 // otherwise poses problems when the aggregate is not
2575 if (htmlElement && htmlElement->renderer())
2576 result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2577 if (bodyElement && bodyElement->renderer())
2578 result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2583 bool FrameView::hasCustomScrollbars() const
2585 const HashSet<RefPtr<Widget> >* viewChildren = children();
2586 HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
2587 for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
2588 Widget* widget = current->get();
2589 if (widget->isFrameView()) {
2590 if (toFrameView(widget)->hasCustomScrollbars())
2592 } else if (widget->isScrollbar()) {
2593 Scrollbar* scrollbar = static_cast<Scrollbar*>(widget);
2594 if (scrollbar->isCustomScrollbar())
2602 FrameView* FrameView::parentFrameView() const
2607 if (Frame* parentFrame = m_frame->tree().parent())
2608 return parentFrame->view();
2613 void FrameView::updateControlTints()
2615 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
2616 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
2617 // This is only done if the theme supports control tinting. It's up to the theme and platform
2618 // to define when controls get the tint and to call this function when that changes.
2620 // Optimize the common case where we bring a window to the front while it's still empty.
2621 if (m_frame->document()->url().isEmpty())
2624 // FIXME: Why do we need this for hasCustomScrollbars?
2625 // FIXME: supportsControlTints is currently true for a bunch of platforms.
2626 // It should only be for Mac 10.6.
2627 if (!RenderTheme::theme().supportsControlTints() && !hasCustomScrollbars())
2632 // FIXME: The use of paint seems like overkill: crbug.com/236892
2633 GraphicsContext context(0); // NULL canvas to get a non-painting context.
2634 context.setUpdatingControlTints(true);
2635 paint(&context, frameRect());
2638 bool FrameView::wasScrolledByUser() const
2640 return m_wasScrolledByUser;
2643 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
2645 if (m_inProgrammaticScroll)
2647 m_maintainScrollPositionAnchor = 0;
2648 m_wasScrolledByUser = wasScrolledByUser;
2651 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
2653 Document* document = m_frame->document();
2657 if (document->printing())
2658 fillWithRed = false; // Printing, don't fill with red (can't remember why).
2659 else if (m_frame->ownerElement())
2660 fillWithRed = false; // Subframe, don't fill with red.
2661 else if (isTransparent())
2662 fillWithRed = false; // Transparent, don't fill with red.
2663 else if (m_paintBehavior & PaintBehaviorSelectionOnly)
2664 fillWithRed = false; // Selections are transparent, don't fill with red.
2665 else if (m_nodeToDraw)
2666 fillWithRed = false; // Element images are transparent, don't fill with red.
2671 p->fillRect(rect, Color(0xFF, 0, 0));
2674 RenderView* renderView = this->renderView();
2676 WTF_LOG_ERROR("called FrameView::paint with nil renderer");
2680 ASSERT(!needsLayout());
2684 InspectorInstrumentation::willPaint(renderView, 0);
2686 bool isTopLevelPainter = !s_inPaintContents;
2687 s_inPaintContents = true;
2689 FontCachePurgePreventer fontCachePurgePreventer;
2691 PaintBehavior oldPaintBehavior = m_paintBehavior;
2693 if (FrameView* parentView = parentFrameView()) {
2694 if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
2695 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2698 if (m_paintBehavior == PaintBehaviorNormal)
2699 document->markers()->invalidateRenderedRectsForMarkersInRect(rect);
2701 if (document->printing())
2702 m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2704 ASSERT(!m_isPainting);
2705 m_isPainting = true;
2707 // m_nodeToDraw is used to draw only one element (and its descendants)
2708 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
2709 RenderLayer* rootLayer = renderView->layer();
2712 renderView->assertSubtreeIsLaidOut();
2713 RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(rootLayer->renderer());
2716 RenderObject* enclosingLayerRenderer = eltRenderer->enclosingLayer() ? eltRenderer->enclosingLayer()->renderer() : eltRenderer;
2717 rootLayer->paint(p, rect, m_paintBehavior, enclosingLayerRenderer);
2719 if (rootLayer->containsDirtyOverlayScrollbars())
2720 rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, eltRenderer);
2722 m_isPainting = false;
2724 m_paintBehavior = oldPaintBehavior;
2725 m_lastPaintTime = currentTime();
2727 // Regions may have changed as a result of the visibility/z-index of element changing.
2728 if (document->annotatedRegionsDirty())
2729 updateAnnotatedRegions();
2731 if (isTopLevelPainter) {
2732 // Everythin that happens after paintContents completions is considered
2733 // to be part of the next frame.
2734 s_currentFrameTimeStamp = currentTime();
2735 s_inPaintContents = false;
2738 InspectorInstrumentation::didPaint(renderView, 0, p, rect);
2741 void FrameView::setPaintBehavior(PaintBehavior behavior)
2743 m_paintBehavior = behavior;
2746 PaintBehavior FrameView::paintBehavior() const
2748 return m_paintBehavior;
2751 bool FrameView::isPainting() const
2753 return m_isPainting;
2756 void FrameView::setNodeToDraw(Node* node)
2758 m_nodeToDraw = node;
2761 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
2763 if (context->paintingDisabled())
2766 if (m_frame->document()->printing())
2769 if (isMainFrame()) {
2770 if (m_frame->page()->chrome().client().paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect))
2774 ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
2777 void FrameView::updateLayoutAndStyleIfNeededRecursive()
2779 // We have to crawl our entire tree looking for any FrameViews that need
2780 // layout and make sure they are up to date.
2781 // Mac actually tests for intersection with the dirty region and tries not to
2782 // update layout for frames that are outside the dirty region. Not only does this seem
2783 // pointless (since those frames will have set a zero timer to layout anyway), but
2784 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2785 // region but then become included later by the second frame adding rects to the dirty region
2786 // when it lays out.
2788 m_frame->document()->updateStyleIfNeeded();
2793 // FIXME: Calling layout() shouldn't trigger scripe execution or have any
2794 // observable effects on the frame tree but we're not quite there yet.
2795 Vector<RefPtr<FrameView> > frameViews;
2796 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2797 if (FrameView* view = child->view())
2798 frameViews.append(view);
2801 const Vector<RefPtr<FrameView> >::iterator end = frameViews.end();
2802 for (Vector<RefPtr<FrameView> >::iterator it = frameViews.begin(); it != end; ++it)
2803 (*it)->updateLayoutAndStyleIfNeededRecursive();
2805 // This assert ensures that parent frames are clean, when child frames finished updating layout and style.
2806 ASSERT(!needsLayout());
2809 void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize)
2811 ASSERT(!enable || !minSize.isEmpty());
2812 ASSERT(minSize.width() <= maxSize.width());
2813 ASSERT(minSize.height() <= maxSize.height());
2815 if (m_shouldAutoSize == enable && m_minAutoSize == minSize && m_maxAutoSize == maxSize)
2819 m_shouldAutoSize = enable;
2820 m_minAutoSize = minSize;
2821 m_maxAutoSize = maxSize;
2822 m_didRunAutosize = false;
2824 setLayoutSizeFixedToFrameSize(enable);
2827 if (m_shouldAutoSize)
2830 // Since autosize mode forces the scrollbar mode, change them to being auto.
2831 setVerticalScrollbarLock(false);
2832 setHorizontalScrollbarLock(false);
2833 setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
2836 void FrameView::forceLayout(bool allowSubtree)
2838 layout(allowSubtree);
2841 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2843 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2844 // the state of things before and after the layout
2845 if (RenderView* renderView = this->renderView()) {
2846 float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2847 float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2849 LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2850 LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2851 renderView->setLogicalWidth(flooredPageLogicalWidth);
2852 renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2853 renderView->setNeedsLayoutAndPrefWidthsRecalc();
2856 // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2857 // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2858 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
2859 // implementation should not do this!
2860 bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode();
2861 const LayoutRect& documentRect = renderView->documentRect();
2862 LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2863 if (docLogicalWidth > pageLogicalWidth) {
2864 int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor);
2865 int expectedPageHeight = std::min<float>(documentRect.height(), pageSize.height() * maximumShrinkFactor);
2866 FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), FloatSize(expectedPageWidth, expectedPageHeight));
2867 pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2868 pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2870 flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2871 flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2872 renderView->setLogicalWidth(flooredPageLogicalWidth);
2873 renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2874 renderView->setNeedsLayoutAndPrefWidthsRecalc();
2877 const LayoutRect& updatedDocumentRect = renderView->documentRect();
2878 LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2879 LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2880 LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2881 LayoutUnit clippedLogicalLeft = 0;
2882 if (!renderView->style()->isLeftToRightDirection())
2883 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2884 LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2886 if (!horizontalWritingMode)
2887 overflow = overflow.transposedRect();
2888 renderView->clearLayoutOverflow();
2889 renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2896 IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const
2898 IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
2900 // Convert from page ("absolute") to FrameView coordinates.
2901 rect.moveBy(-scrollPosition());
2906 IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const
2908 IntRect rect = viewRect;
2910 // Convert from FrameView coords into page ("absolute") coordinates.
2911 rect.moveBy(scrollPosition());
2913 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2914 // move the rect for now.
2915 rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms)));
2919 IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const
2921 IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms));
2923 // Convert from page ("absolute") to FrameView coordinates.
2924 point.moveBy(-scrollPosition());
2928 IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const
2930 IntPoint point = viewPoint;
2932 // Convert from FrameView coords into page ("absolute") coordinates.
2933 point += IntSize(scrollX(), scrollY());
2935 return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms));
2938 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2940 if (const ScrollView* parentScrollView = toScrollView(parent())) {
2941 if (parentScrollView->isFrameView()) {
2942 const FrameView* parentView = toFrameView(parentScrollView);
2943 // Get our renderer in the parent view
2944 RenderPart* renderer = m_frame->ownerRenderer();
2948 IntRect rect(localRect);
2949 // Add borders and padding??
2950 rect.move(renderer->borderLeft() + renderer->paddingLeft(),
2951 renderer->borderTop() + renderer->paddingTop());
2952 return parentView->convertFromRenderer(renderer, rect);
2955 return Widget::convertToContainingView(localRect);
2961 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
2963 if (const ScrollView* parentScrollView = toScrollView(parent())) {
2964 if (parentScrollView->isFrameView()) {
2965 const FrameView* parentView = toFrameView(parentScrollView);
2967 // Get our renderer in the parent view
2968 RenderPart* renderer = m_frame->ownerRenderer();
2972 IntRect rect = parentView->convertToRenderer(renderer, parentRect);
2973 // Subtract borders and padding
2974 rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
2975 -renderer->borderTop() - renderer->paddingTop());
2979 return Widget::convertFromContainingView(parentRect);
2985 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
2987 if (const ScrollView* parentScrollView = toScrollView(parent())) {
2988 if (parentScrollView->isFrameView()) {
2989 const FrameView* parentView = toFrameView(parentScrollView);
2991 // Get our renderer in the parent view
2992 RenderPart* renderer = m_frame->ownerRenderer();
2996 IntPoint point(localPoint);
2998 // Add borders and padding
2999 point.move(renderer->borderLeft() + renderer->paddingLeft(),
3000 renderer->borderTop() + renderer->paddingTop());
3001 return parentView->convertFromRenderer(renderer, point);
3004 return Widget::convertToContainingView(localPoint);
3010 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
3012 if (const ScrollView* parentScrollView = toScrollView(parent())) {
3013 if (parentScrollView->isFrameView()) {
3014 const FrameView* parentView = toFrameView(parentScrollView);
3016 // Get our renderer in the parent view
3017 RenderPart* renderer = m_frame->ownerRenderer();
3021 IntPoint point = parentView->convertToRenderer(renderer, parentPoint);
3022 // Subtract borders and padding
3023 point.move(-renderer->borderLeft() - renderer->paddingLeft(),
3024 -renderer->borderTop() - renderer->paddingTop());
3028 return Widget::convertFromContainingView(parentPoint);
3034 void FrameView::setTracksRepaints(bool trackRepaints)
3036 if (trackRepaints == m_isTrackingRepaints)
3039 for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
3040 if (RenderView* renderView = frame->contentRenderer())
3041 renderView->compositor()->setTracksRepaints(trackRepaints);
3044 resetTrackedRepaints();
3045 m_isTrackingRepaints = trackRepaints;
3048 void FrameView::resetTrackedRepaints()
3050 m_trackedRepaintRects.clear();
3051 if (RenderView* renderView = this->renderView())
3052 renderView->compositor()->resetTrackedRepaintRects();
3055 String FrameView::trackedRepaintRectsAsText() const
3058 if (!m_trackedRepaintRects.isEmpty()) {
3059 ts << "(repaint rects\n";
3060 for (size_t i = 0; i < m_trackedRepaintRects.size(); ++i)
3061 ts << " (rect " << m_trackedRepaintRects[i].x() << " " << m_trackedRepaintRects[i].y() << " " << m_trackedRepaintRects[i].width() << " " << m_trackedRepaintRects[i].height() << ")\n";
3064 return ts.release();
3067 void FrameView::addResizerArea(RenderBox* resizerBox)
3069 if (!m_resizerAreas)
3070 m_resizerAreas = adoptPtr(new ResizerAreaSet);
3071 m_resizerAreas->add(resizerBox);
3074 void FrameView::removeResizerArea(RenderBox* resizerBox)
3076 if (!m_resizerAreas)
3079 ResizerAreaSet::iterator it = m_resizerAreas->find(resizerBox);
3080 if (it != m_resizerAreas->end())
3081 m_resizerAreas->remove(it);
3084 bool FrameView::addScrollableArea(ScrollableArea* scrollableArea)
3086 ASSERT(scrollableArea);
3087 if (!m_scrollableAreas)
3088 m_scrollableAreas = adoptPtr(new ScrollableAreaSet);
3089 return m_scrollableAreas->add(scrollableArea).isNewEntry;
3092 bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
3094 if (!m_scrollableAreas)
3097 ScrollableAreaSet::iterator it = m_scrollableAreas->find(scrollableArea);
3098 if (it == m_scrollableAreas->end())
3101 m_scrollableAreas->remove(it);
3105 bool FrameView::containsScrollableArea(const ScrollableArea* scrollableArea) const
3107 ASSERT(scrollableArea);
3108 if (!m_scrollableAreas || !scrollableArea)
3110 return m_scrollableAreas->contains(const_cast<ScrollableArea*>(scrollableArea));
3113 void FrameView::removeChild(Widget* widget)
3115 if (widget->isFrameView())
3116 removeScrollableArea(toFrameView(widget));
3118 ScrollView::removeChild(widget);
3121 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
3123 // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
3124 // should handle wheel events.
3125 #if !USE(RUBBER_BANDING)
3126 if (!isScrollable())
3130 // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
3131 if (!canHaveScrollbars())
3134 return ScrollableArea::handleWheelEvent(wheelEvent);
3137 bool FrameView::isVerticalDocument() const
3139 RenderView* renderView = this->renderView();
3143 return renderView->style()->isHorizontalWritingMode();
3146 bool FrameView::isFlippedDocument() const
3148 RenderView* renderView = this->renderView();
3152 return renderView->style()->isFlippedBlocksWritingMode();
3155 AXObjectCache* FrameView::axObjectCache() const
3157 if (frame().document())
3158 return frame().document()->existingAXObjectCache();
3162 void FrameView::setCursor(const Cursor& cursor)
3164 Page* page = frame().page();
3167 page->chrome().setCursor(cursor);
3170 bool FrameView::isMainFrame() const
3172 return m_frame->isMainFrame();
3175 void FrameView::frameRectsChanged()
3177 if (layoutSizeFixedToFrameSize())
3178 setLayoutSizeInternal(frameRect().size());
3180 ScrollView::frameRectsChanged();
3183 void FrameView::setLayoutSizeInternal(const IntSize& size)
3185 if (m_layoutSize == size)
3188 m_layoutSize = size;
3192 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3194 ScrollableArea::didAddScrollbar(scrollbar, orientation);
3195 if (AXObjectCache* cache = axObjectCache())
3196 cache->handleScrollbarUpdate(this);
3199 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3201 ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
3202 if (AXObjectCache* cache = axObjectCache()) {
3203 cache->remove(scrollbar);
3204 cache->handleScrollbarUpdate(this);
3208 } // namespace WebCore