diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/page/FrameView.cpp | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/page/FrameView.cpp')
-rw-r--r-- | Source/WebCore/page/FrameView.cpp | 1252 |
1 files changed, 879 insertions, 373 deletions
diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index 083b83ad5..209030309 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -28,19 +28,24 @@ #include "FrameView.h" #include "AXObjectCache.h" +#include "AnimationController.h" #include "BackForwardController.h" +#include "CachedImage.h" #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" +#include "DOMWindow.h" #include "DocumentMarkerController.h" #include "EventHandler.h" #include "FloatRect.h" #include "FocusController.h" #include "FontCache.h" +#include "FontLoader.h" #include "Frame.h" #include "FrameActionScheduler.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "FrameSelection.h" #include "FrameTree.h" #include "GraphicsContext.h" #include "HTMLDocument.h" @@ -52,14 +57,17 @@ #include "InspectorController.h" #include "InspectorInstrumentation.h" #include "OverflowEvent.h" +#include "ProgressTracker.h" #include "RenderArena.h" #include "RenderEmbeddedObject.h" #include "RenderFullScreen.h" #include "RenderIFrame.h" #include "RenderLayer.h" +#include "RenderLayerBacking.h" #include "RenderPart.h" #include "RenderScrollbar.h" #include "RenderScrollbarPart.h" +#include "RenderStyle.h" #include "RenderTheme.h" #include "RenderView.h" #include "ScrollAnimator.h" @@ -71,7 +79,6 @@ #include <wtf/CurrentTime.h> #include <wtf/TemporaryChange.h> -#include <wtf/UnusedParam.h> #if USE(ACCELERATED_COMPOSITING) #include "RenderLayerCompositor.h" @@ -123,16 +130,13 @@ double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0; // The maximum number of updateWidgets iterations that should be done before returning. static const unsigned maxUpdateWidgetsIterations = 2; -static inline RenderView* rootRenderer(const FrameView* view) -{ - return view->frame() ? view->frame()->contentRenderer() : 0; -} - static RenderLayer::UpdateLayerPositionsFlags updateLayerPositionFlags(RenderLayer* layer, bool isRelayoutingSubtree, bool didFullRepaint) { RenderLayer::UpdateLayerPositionsFlags flags = RenderLayer::defaultFlags; - if (didFullRepaint) + if (didFullRepaint) { flags &= ~RenderLayer::CheckForRepaint; + flags |= RenderLayer::NeedsFullRepaintInBacking; + } if (isRelayoutingSubtree && layer->isPaginated()) flags |= RenderLayer::UpdatePagination; return flags; @@ -168,7 +172,6 @@ Pagination::Mode paginationModeForRenderStyle(RenderStyle* style) FrameView::FrameView(Frame* frame) : m_frame(frame) , m_canHaveScrollbars(true) - , m_slowRepaintObjectCount(0) , m_layoutTimer(this, &FrameView::layoutTimerFired) , m_layoutRoot(0) , m_inSynchronousPostLayout(false) @@ -192,9 +195,14 @@ FrameView::FrameView(Frame* frame) , m_shouldAutoSize(false) , m_inAutoSize(false) , m_didRunAutosize(false) + , m_headerHeight(0) + , m_footerHeight(0) + , m_milestonesPendingPaint(0) #if ENABLE(CSS_FILTERS) , m_hasSoftwareFilters(false) #endif + , m_visualUpdatesAllowedByClient(true) + , m_scrollPinningBehavior(DoNotPin) { init(); @@ -234,9 +242,7 @@ FrameView::~FrameView() m_actionScheduler->clear(); } - if (AXObjectCache::accessibilityEnabled() && axObjectCache()) - axObjectCache()->remove(this); - + removeFromAXObjectCache(); resetScrollbars(); // Custom scrollbars should already be destroyed at this point @@ -299,9 +305,10 @@ void FrameView::reset() m_disableRepaints = 0; } -bool FrameView::isFrameView() const -{ - return true; +void FrameView::removeFromAXObjectCache() +{ + if (AXObjectCache* cache = axObjectCache()) + cache->remove(this); } void FrameView::clearFrame() @@ -340,7 +347,7 @@ void FrameView::init() // Propagate the marginwidth/height and scrolling modes to the view. Element* ownerElement = m_frame ? m_frame->ownerElement() : 0; if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { - HTMLFrameElementBase* frameElt = static_cast<HTMLFrameElementBase*>(ownerElement); + HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement); if (frameElt->scrollingMode() == ScrollbarAlwaysOff) setCanHaveScrollbars(false); LayoutUnit marginWidth = frameElt->marginWidth(); @@ -350,6 +357,23 @@ void FrameView::init() if (marginHeight != -1) setMarginHeight(marginHeight); } + + Page* page = frame() ? frame()->page() : 0; + if (page && page->chrome().client()->shouldPaintEntireContents()) + setPaintsEntireContents(true); +} + +void FrameView::prepareForDetach() +{ + detachCustomScrollbars(); + // When the view is no longer associated with a frame, it needs to be removed from the ax object cache + // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later. + removeFromAXObjectCache(); + + if (m_frame && m_frame->page()) { + if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) + scrollingCoordinator->willDestroyScrollableArea(this); + } } void FrameView::detachCustomScrollbars() @@ -374,20 +398,13 @@ void FrameView::recalculateScrollbarOverlayStyle() ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault; Color backgroundColor = documentBackgroundColor(); -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - RenderLayerCompositor* compositor = root->compositor(); - compositor->documentBackgroundColorDidChange(); - } -#endif - if (backgroundColor.isValid()) { // Reduce the background color from RGB to a lightness value // and determine which scrollbar style to use based on a lightness // heuristic. double hue, saturation, lightness; backgroundColor.getHSL(hue, saturation, lightness); - if (lightness <= .5) + if (lightness <= .5 && backgroundColor.alpha() > 0) overlayStyle = ScrollbarOverlayStyleLight; } @@ -417,8 +434,8 @@ bool FrameView::didFirstLayout() const void FrameView::invalidateRect(const IntRect& rect) { if (!parent()) { - if (hostWindow()) - hostWindow()->invalidateContentsAndRootView(rect, false /*immediate*/); + if (HostWindow* window = hostWindow()) + window->invalidateContentsAndRootView(rect, false /*immediate*/); return; } @@ -441,23 +458,37 @@ void FrameView::setFrameRect(const IntRect& newRect) if (newRect == oldRect) return; +#if ENABLE(TEXT_AUTOSIZING) + // Autosized font sizes depend on the width of the viewing area. + if (newRect.width() != oldRect.width()) { + Page* page = m_frame ? m_frame->page() : 0; + if (page && page->mainFrame() == m_frame && page->settings()->textAutosizingEnabled()) { + for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) + m_frame->document()->textAutosizer()->recalculateMultipliers(); + } + } +#endif + ScrollView::setFrameRect(newRect); updateScrollableAreaSet(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidChangeSize(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidChangeSize(); } #endif + + if (!frameFlatteningEnabled()) + sendResizeEventIfNeeded(); } #if ENABLE(REQUEST_ANIMATION_FRAME) bool FrameView::scheduleAnimation() { - if (hostWindow()) { - hostWindow()->scheduleAnimation(); + if (HostWindow* window = hostWindow()) { + window->scheduleAnimation(); return true; } return false; @@ -476,21 +507,35 @@ void FrameView::setMarginHeight(LayoutUnit h) m_margins.setHeight(h); } -bool FrameView::avoidScrollbarCreation() const +bool FrameView::frameFlatteningEnabled() const { - ASSERT(m_frame); + Settings* settings = frame() ? frame()->settings() : 0; + if (!settings) + return false; - // with frame flattening no subframe can have scrollbars - // but we also cannot turn scrollbars off as we determine - // our flattening policy using that. + return settings->frameFlatteningEnabled(); +} - if (!m_frame->ownerElement()) +bool FrameView::isFrameFlatteningValidForThisFrame() const +{ + if (!frameFlatteningEnabled()) return false; - if (!m_frame->settings() || m_frame->settings()->frameFlatteningEnabled()) - return true; + HTMLFrameOwnerElement* owner = frame() ? frame()->ownerElement() : 0; + if (!owner) + return false; - return false; + // Frame flattening is valid only for <frame> and <iframe>. + return owner->hasTagName(frameTag) || owner->hasTagName(iframeTag); +} + +bool FrameView::avoidScrollbarCreation() const +{ + ASSERT(m_frame); + // with frame flattening no subframe can have scrollbars + // but we also cannot turn scrollbars off as we determine + // our flattening policy using that. + return isFrameFlatteningValidForThisFrame(); } void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) @@ -555,7 +600,7 @@ void FrameView::setContentsSize(const IntSize& size) updateScrollableAreaSet(); - page->chrome()->contentsSizeChanged(frame(), size); //notify only + page->chrome().contentsSizeChanged(frame(), size); // Notify only. m_deferSetNeedsLayouts--; @@ -565,13 +610,13 @@ void FrameView::setContentsSize(const IntSize& size) void FrameView::adjustViewSize() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; ASSERT(m_frame->view() == this); - const IntRect rect = root->documentRect(); + const IntRect rect = renderView->documentRect(); const IntSize& size = rect.size(); ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize()); @@ -586,9 +631,11 @@ void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, S // use the root element. // To combat the inability to scroll on a page with overflow:hidden on the root when scaled, disregard hidden when - // there is a frameScaleFactor that is greater than one on the main frame. + // there is a frameScaleFactor that is greater than one on the main frame. Also disregard hidden if there is a + // header or footer. - bool overrideHidden = m_frame->page() && m_frame->page()->mainFrame() == m_frame && m_frame->frameScaleFactor() > 1; + bool overrideHidden = (m_frame->page() && m_frame->page()->mainFrame() == m_frame && m_frame->frameScaleFactor() > 1) + || (m_frame->page() && m_frame->page()->mainFrame() == m_frame && (headerHeight() || footerHeight())); EOverflow overflowX = o->style()->overflowX(); EOverflow overflowY = o->style()->overflowY(); @@ -683,7 +730,11 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) { hMode = ScrollbarAuto; - vMode = ScrollbarAuto; + // Seamless documents begin with heights of 0; we special case that here + // to correctly render documents that don't need scrollbars. + IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size(); + bool isSeamlessDocument = frame() && frame()->document() && frame()->document()->shouldDisplaySeamlesslyWithParent(); + vMode = (isSeamlessDocument && !fullVisibleSize.height()) ? ScrollbarAlwaysOff : ScrollbarAuto; } else { hMode = ScrollbarAlwaysOff; vMode = ScrollbarAlwaysOff; @@ -695,7 +746,7 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0; Node* body = document->body(); if (body && body->renderer()) { - if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) { + if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { vMode = ScrollbarAlwaysOff; hMode = ScrollbarAlwaysOff; } else if (body->hasTagName(bodyTag)) { @@ -712,37 +763,37 @@ void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, Scrollbar #if USE(ACCELERATED_COMPOSITING) void FrameView::updateCompositingLayersAfterStyleChange() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; // If we expect to update compositing after an incipient layout, don't do so here. - if (m_doingPreLayoutStyleUpdate || layoutPending() || root->needsLayout()) + if (m_doingPreLayoutStyleUpdate || layoutPending() || renderView->needsLayout()) return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref - root->compositor()->cacheAcceleratedCompositingFlags(); - root->compositor()->updateCompositingLayers(CompositingUpdateAfterStyleChange); + renderView->compositor()->cacheAcceleratedCompositingFlags(); + renderView->compositor()->updateCompositingLayers(CompositingUpdateAfterStyleChange); } void FrameView::updateCompositingLayersAfterLayout() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref - root->compositor()->cacheAcceleratedCompositingFlags(); - root->compositor()->updateCompositingLayers(CompositingUpdateAfterLayout); + renderView->compositor()->cacheAcceleratedCompositingFlags(); + renderView->compositor()->updateCompositingLayers(CompositingUpdateAfterLayout); } void FrameView::clearBackingStores() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; - RenderLayerCompositor* compositor = root->compositor(); + RenderLayerCompositor* compositor = renderView->compositor(); ASSERT(compositor->inCompositingMode()); compositor->enableCompositingMode(false); compositor->clearBackingForAllLayers(); @@ -750,46 +801,64 @@ void FrameView::clearBackingStores() void FrameView::restoreBackingStores() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return; - RenderLayerCompositor* compositor = root->compositor(); + RenderLayerCompositor* compositor = renderView->compositor(); compositor->enableCompositingMode(true); compositor->updateCompositingLayers(CompositingUpdateAfterLayout); } +bool FrameView::usesCompositedScrolling() const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return false; + if (m_frame->settings() && m_frame->settings()->compositedScrollingForFramesEnabled()) + return renderView->compositor()->inForcedCompositingMode(); + return false; +} + +GraphicsLayer* FrameView::layerForScrolling() const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return 0; + return renderView->compositor()->scrollLayer(); +} + GraphicsLayer* FrameView::layerForHorizontalScrollbar() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForHorizontalScrollbar(); + return renderView->compositor()->layerForHorizontalScrollbar(); } GraphicsLayer* FrameView::layerForVerticalScrollbar() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForVerticalScrollbar(); + return renderView->compositor()->layerForVerticalScrollbar(); } GraphicsLayer* FrameView::layerForScrollCorner() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForScrollCorner(); + return renderView->compositor()->layerForScrollCorner(); } TiledBacking* FrameView::tiledBacking() { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - RenderLayerBacking* backing = root->layer()->backing(); + RenderLayerBacking* backing = renderView->layer()->backing(); if (!backing) return 0; @@ -798,11 +867,11 @@ TiledBacking* FrameView::tiledBacking() uint64_t FrameView::scrollLayerID() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - RenderLayerBacking* backing = root->layer()->backing(); + RenderLayerBacking* backing = renderView->layer()->backing(); if (!backing) return 0; @@ -812,17 +881,44 @@ uint64_t FrameView::scrollLayerID() const #if ENABLE(RUBBER_BANDING) GraphicsLayer* FrameView::layerForOverhangAreas() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - return root->compositor()->layerForOverhangAreas(); + return renderView->compositor()->layerForOverhangAreas(); +} + +GraphicsLayer* FrameView::setWantsLayerForTopOverHangArea(bool wantsLayer) const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return 0; + + return renderView->compositor()->updateLayerForTopOverhangArea(wantsLayer); +} + +GraphicsLayer* FrameView::setWantsLayerForBottomOverHangArea(bool wantsLayer) const +{ + RenderView* renderView = this->renderView(); + if (!renderView) + return 0; + + return renderView->compositor()->updateLayerForBottomOverhangArea(wantsLayer); +} + +#endif // ENABLE(RUBBER_BANDING) + +bool FrameView::scrollbarAnimationsAreSuppressed() const +{ + Page* page = frame() ? frame()->page() : 0; + if (!page) + return true; + return page->shouldSuppressScrollbarAnimations(); } -#endif bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return true; // We don't want to keep trying to update layers if we have no renderer. ASSERT(m_frame->view() == this); @@ -836,7 +932,7 @@ bool FrameView::flushCompositingStateForThisFrame(Frame* rootFrameForFlush) // visible flash to occur. Instead, stop the deferred repaint timer and repaint immediately. flushDeferredRepaints(); - root->compositor()->flushPendingLayerChanges(rootFrameForFlush == m_frame); + renderView->compositor()->flushPendingLayerChanges(rootFrameForFlush == m_frame); return true; } @@ -845,16 +941,36 @@ void FrameView::setNeedsOneShotDrawingSynchronization() { Page* page = frame() ? frame()->page() : 0; if (page) - page->chrome()->client()->setNeedsOneShotDrawingSynchronization(); + page->chrome().client()->setNeedsOneShotDrawingSynchronization(); } #endif // USE(ACCELERATED_COMPOSITING) +void FrameView::setHeaderHeight(int headerHeight) +{ + if (m_frame && m_frame->page()) + ASSERT(m_frame == m_frame->page()->mainFrame()); + m_headerHeight = headerHeight; + + if (RenderView* renderView = this->renderView()) + renderView->setNeedsLayout(true); +} + +void FrameView::setFooterHeight(int footerHeight) +{ + if (m_frame && m_frame->page()) + ASSERT(m_frame == m_frame->page()->mainFrame()); + m_footerHeight = footerHeight; + + if (RenderView* renderView = this->renderView()) + renderView->setNeedsLayout(true); +} + bool FrameView::hasCompositedContent() const { #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) - return root->compositor()->inCompositingMode(); + if (RenderView* renderView = this->renderView()) + return renderView->compositor()->inCompositingMode(); #endif return false; } @@ -894,10 +1010,10 @@ bool FrameView::hasCompositingAncestor() const void FrameView::enterCompositingMode() { #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - root->compositor()->enableCompositingMode(); + if (RenderView* renderView = this->renderView()) { + renderView->compositor()->enableCompositingMode(); if (!needsLayout()) - root->compositor()->scheduleCompositingLayerUpdate(); + renderView->compositor()->scheduleCompositingLayerUpdate(); } #endif } @@ -933,11 +1049,8 @@ bool FrameView::flushCompositingStateIncludingSubframes() bool FrameView::isSoftwareRenderable() const { #if USE(ACCELERATED_COMPOSITING) - RenderView* root = rootRenderer(this); - if (!root) - return true; - - return !root->compositor()->has3DContent(); + RenderView* renderView = this->renderView(); + return !renderView || !renderView->compositor()->has3DContent(); #else return true; #endif @@ -945,18 +1058,31 @@ bool FrameView::isSoftwareRenderable() const void FrameView::didMoveOnscreen() { - if (RenderView* root = rootRenderer(this)) - root->didMoveOnscreen(); contentAreaDidShow(); } void FrameView::willMoveOffscreen() { - if (RenderView* root = rootRenderer(this)) - root->willMoveOffscreen(); contentAreaDidHide(); } +void FrameView::setIsInWindow(bool isInWindow) +{ + if (RenderView* renderView = this->renderView()) + renderView->setIsInWindow(isInWindow); + + if (isInWindow) + resumeAnimatingImages(); +} + +void FrameView::resumeAnimatingImages() +{ + // Drawing models which cache painted content while out-of-window (WebKit2's composited drawing areas, etc.) + // require that we repaint animated images to kickstart the animation loop. + + CachedImage::resumeAnimatingImagesForLoader(frame()->document()->cachedResourceLoader()); +} + RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const { return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot; @@ -971,7 +1097,7 @@ static inline void collectFrameViewChildren(FrameView* frameView, Vector<RefPtr< for (HashSet<RefPtr<Widget> >::iterator current = viewChildren->begin(); current != end; ++current) { Widget* widget = (*current).get(); if (widget->isFrameView()) - frameViews.append(static_cast<FrameView*>(widget)); + frameViews.append(toFrameView(widget)); } } @@ -1016,6 +1142,9 @@ void FrameView::layout(bool allowSubtree) // Protect the view from being deleted during layout (in recalcStyle) RefPtr<FrameView> protector(this); + // Every scroll that happens during layout is programmatic. + TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); + bool inChildFrameLayoutWithFrameFlattening = isInChildFrameWithFrameFlattening(); if (inChildFrameLayoutWithFrameFlattening) { @@ -1065,9 +1194,10 @@ void FrameView::layout(bool allowSubtree) } // Viewport-dependent media queries may cause us to need completely different style information. - // Check that here. - if (document->styleResolver()->affectedByViewportChange()) { - document->styleResolverChanged(RecalcStyleImmediately); + if (!document->styleResolverIfExists() || document->styleResolverIfExists()->affectedByViewportChange()) { + document->styleResolverChanged(DeferRecalcStyle); + // FIXME: This instrumentation event is not strictly accurate since cached media query results + // do not persist across StyleResolver rebuilds. InspectorInstrumentation::mediaQueryResultChanged(document); } else document->evaluateMediaQueryList(); @@ -1108,7 +1238,7 @@ void FrameView::layout(bool allowSubtree) Document* document = m_frame->document(); Node* body = document->body(); if (body && body->renderer()) { - if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) { + if (body->hasTagName(framesetTag) && !frameFlatteningEnabled()) { body->renderer()->setChildNeedsLayout(true); } else if (body->hasTagName(bodyTag)) { if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox()->stretchesToViewport()) @@ -1144,7 +1274,7 @@ void FrameView::layout(bool allowSubtree) if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) m_lastViewportSize = fixedLayoutSize(); else - m_lastViewportSize = visibleContentRect(true /*includeScrollbars*/).size(); + m_lastViewportSize = visibleContentRect(IncludeScrollbars).size(); m_lastZoomFactor = root->style()->zoom(); // Set the initial vMode to AlwaysOn if we're auto. @@ -1208,16 +1338,20 @@ void FrameView::layout(bool allowSubtree) m_layoutRoot = 0; } // Reset m_layoutSchedulingEnabled to its previous value. + bool neededFullRepaint = m_doFullRepaint; + if (!subtree && !toRenderView(root)->printing()) adjustViewSize(); + m_doFullRepaint = neededFullRepaint; + // Now update the positions of all layers. beginDeferredRepaints(); if (m_doFullRepaint) root->view()->repaint(); // FIXME: This isn't really right, since the RenderView doesn't fully encompass the visibleContentRect(). It just happens // to work out most of the time, since first layouts and printing don't have you scrolled anywhere. - layer->updateLayerPositionsAfterLayout(rootRenderer(this)->layer(), updateLayerPositionFlags(layer, subtree, m_doFullRepaint)); + layer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layer, subtree, m_doFullRepaint)); endDeferredRepaints(); @@ -1227,9 +1361,9 @@ void FrameView::layout(bool allowSubtree) m_layoutCount++; -#if PLATFORM(MAC) || PLATFORM(CHROMIUM) - if (AXObjectCache::accessibilityEnabled()) - root->document()->axObjectCache()->postNotification(root, AXObjectCache::AXLayoutComplete, true); +#if PLATFORM(MAC) || PLATFORM(WIN) + if (AXObjectCache* cache = root->document()->existingAXObjectCache()) + cache->postNotification(root, AXObjectCache::AXLayoutComplete, true); #endif #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION) updateAnnotatedRegions(); @@ -1246,8 +1380,8 @@ void FrameView::layout(bool allowSubtree) if (!m_postLayoutTasksTimer.isActive()) { if (!m_inSynchronousPostLayout) { if (inChildFrameLayoutWithFrameFlattening) { - if (RenderView* root = rootRenderer(this)) - root->updateWidgetPositions(); + if (RenderView* renderView = this->renderView()) + renderView->updateWidgetPositions(); } else { m_inSynchronousPostLayout = true; // Calls resumeScheduledEvents() @@ -1281,44 +1415,45 @@ void FrameView::layout(bool allowSubtree) if (!page) return; - page->chrome()->client()->layoutUpdated(frame()); + page->chrome().client()->layoutUpdated(frame()); } RenderBox* FrameView::embeddedContentBox() const { #if ENABLE(SVG) - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return 0; - RenderObject* rootChild = root->firstChild(); - if (!rootChild || !rootChild->isBox()) + RenderObject* firstChild = renderView->firstChild(); + if (!firstChild || !firstChild->isBox()) return 0; // Curently only embedded SVG documents participate in the size-negotiation logic. - if (rootChild->isSVGRoot()) - return toRenderBox(rootChild); + if (firstChild->isSVGRoot()) + return toRenderBox(firstChild); #endif return 0; } -void FrameView::addWidgetToUpdate(RenderEmbeddedObject* object) +void FrameView::addWidgetToUpdate(RenderObject* object) { if (!m_widgetUpdateSet) - m_widgetUpdateSet = adoptPtr(new RenderEmbeddedObjectSet); + m_widgetUpdateSet = adoptPtr(new RenderObjectSet); // Tell the DOM element that it needs a widget update. Node* node = object->node(); if (node->hasTagName(objectTag) || node->hasTagName(embedTag)) { - HTMLPlugInImageElement* pluginElement = static_cast<HTMLPlugInImageElement*>(node); - pluginElement->setNeedsWidgetUpdate(true); + HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(node); + if (!pluginElement->needsCheckForSizeChange()) + pluginElement->setNeedsWidgetUpdate(true); } m_widgetUpdateSet->add(object); } -void FrameView::removeWidgetToUpdate(RenderEmbeddedObject* object) +void FrameView::removeWidgetToUpdate(RenderObject* object) { if (!m_widgetUpdateSet) return; @@ -1335,6 +1470,7 @@ String FrameView::mediaType() const { // See if we have an override type. String overrideType = m_frame->loader()->client()->overrideMediaType(); + InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType); if (!overrideType.isNull()) return overrideType; return m_mediaType; @@ -1355,7 +1491,7 @@ void FrameView::adjustMediaTypeForPrinting(bool printing) bool FrameView::useSlowRepaints(bool considerOverlap) const { - bool mustBeSlow = m_slowRepaintObjectCount > 0 || (platformWidget() && hasViewportConstrainedObjects()); + bool mustBeSlow = hasSlowRepaintObjects() || (platformWidget() && hasViewportConstrainedObjects()); // FIXME: WidgetMac.mm makes the assumption that useSlowRepaints == // m_contentIsOpaque, so don't take the fast path for composited layers @@ -1364,13 +1500,6 @@ bool FrameView::useSlowRepaints(bool considerOverlap) const if (contentsInCompositedLayer() && !platformWidget()) return mustBeSlow; -#if PLATFORM(CHROMIUM) - // The chromium compositor does not support scrolling a non-composited frame within a composited page through - // the fast scrolling path, so force slow scrolling in that case. - if (m_frame->ownerElement() && !hasCompositedContent() && m_frame->page() && m_frame->page()->mainFrame()->view()->hasCompositedContent()) - return true; -#endif - bool isOverlapped = m_isOverlapped && considerOverlap; if (mustBeSlow || m_cannotBlitToWindow || isOverlapped || !m_contentIsOpaque) @@ -1398,9 +1527,9 @@ void FrameView::updateCanBlitOnScrollRecursively() bool FrameView::contentsInCompositedLayer() const { #if USE(ACCELERATED_COMPOSITING) - RenderView* root = rootRenderer(this); - if (root && root->isComposited()) { - GraphicsLayer* layer = root->layer()->backing()->graphicsLayer(); + RenderView* renderView = this->renderView(); + if (renderView && renderView->isComposited()) { + GraphicsLayer* layer = renderView->layer()->backing()->graphicsLayer(); if (layer && layer->drawsContent()) return true; } @@ -1414,9 +1543,16 @@ void FrameView::setCannotBlitToWindow() updateCanBlitOnScrollRecursively(); } -void FrameView::addSlowRepaintObject() +void FrameView::addSlowRepaintObject(RenderObject* o) { - if (!m_slowRepaintObjectCount++) { + bool hadSlowRepaintObjects = hasSlowRepaintObjects(); + + if (!m_slowRepaintObjects) + m_slowRepaintObjects = adoptPtr(new RenderObjectSet); + + m_slowRepaintObjects->add(o); + + if (!hadSlowRepaintObjects) { updateCanBlitOnScrollRecursively(); if (Page* page = m_frame->page()) { @@ -1426,11 +1562,14 @@ void FrameView::addSlowRepaintObject() } } -void FrameView::removeSlowRepaintObject() +void FrameView::removeSlowRepaintObject(RenderObject* o) { - ASSERT(m_slowRepaintObjectCount > 0); - m_slowRepaintObjectCount--; - if (!m_slowRepaintObjectCount) { + if (!m_slowRepaintObjects) + return; + + m_slowRepaintObjects->remove(o); + if (m_slowRepaintObjects->isEmpty()) { + m_slowRepaintObjects = nullptr; updateCanBlitOnScrollRecursively(); if (Page* page = m_frame->page()) { @@ -1472,14 +1611,61 @@ void FrameView::removeViewportConstrainedObject(RenderObject* object) } } +LayoutRect FrameView::viewportConstrainedVisibleContentRect() const +{ + LayoutRect viewportRect = visibleContentRect(); + viewportRect.setLocation(toPoint(scrollOffsetForFixedPosition())); + return viewportRect; +} + +IntSize FrameView::scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& totalContentsSize, const IntPoint& scrollPosition, const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, int headerHeight, int footerHeight) +{ + IntPoint constrainedPosition = ScrollableArea::constrainScrollPositionForOverhang(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, headerHeight, footerHeight); + + IntSize maxSize = totalContentsSize - visibleContentRect.size(); + + float dragFactorX = (fixedElementsLayoutRelativeToFrame || !maxSize.width()) ? 1 : (totalContentsSize.width() - visibleContentRect.width() * frameScaleFactor) / maxSize.width(); + float dragFactorY = (fixedElementsLayoutRelativeToFrame || !maxSize.height()) ? 1 : (totalContentsSize.height() - visibleContentRect.height() * frameScaleFactor) / maxSize.height(); + + return IntSize(constrainedPosition.x() * dragFactorX / frameScaleFactor, constrainedPosition.y() * dragFactorY / frameScaleFactor); +} + IntSize FrameView::scrollOffsetForFixedPosition() const { IntRect visibleContentRect = this->visibleContentRect(); - IntSize contentsSize = this->contentsSize(); + IntSize totalContentsSize = this->totalContentsSize(); IntPoint scrollPosition = this->scrollPosition(); IntPoint scrollOrigin = this->scrollOrigin(); float frameScaleFactor = m_frame ? m_frame->frameScaleFactor() : 1; - return WebCore::scrollOffsetForFixedPosition(visibleContentRect, contentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame()); + return scrollOffsetForFixedPosition(visibleContentRect, totalContentsSize, scrollPosition, scrollOrigin, frameScaleFactor, fixedElementsLayoutRelativeToFrame(), headerHeight(), footerHeight()); +} + +IntPoint FrameView::minimumScrollPosition() const +{ + IntPoint minimumPosition(ScrollView::minimumScrollPosition()); + + if (!m_frame || !m_frame->page()) + return minimumPosition; + + if (m_frame == m_frame->page()->mainFrame() && m_scrollPinningBehavior == PinToBottom) + minimumPosition.setY(maximumScrollPosition().y()); + + return minimumPosition; +} + +IntPoint FrameView::maximumScrollPosition() const +{ + IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), totalContentsSize().height() - visibleHeight() - scrollOrigin().y()); + + maximumOffset.clampNegativeToZero(); + + if (!m_frame || !m_frame->page()) + return maximumOffset; + + if (m_frame == m_frame->page()->mainFrame() && m_scrollPinningBehavior == PinToTop) + maximumOffset.setY(minimumScrollPosition().y()); + + return maximumOffset; } bool FrameView::fixedElementsLayoutRelativeToFrame() const @@ -1491,9 +1677,20 @@ bool FrameView::fixedElementsLayoutRelativeToFrame() const return m_frame->settings()->fixedElementsLayoutRelativeToFrame(); } -IntPoint FrameView::currentMousePosition() const +IntPoint FrameView::lastKnownMousePosition() const { - return m_frame ? m_frame->eventHandler()->currentMousePosition() : IntPoint(); + return m_frame ? m_frame->eventHandler()->lastKnownMousePosition() : IntPoint(); +} + +bool FrameView::isHandlingWheelEvent() const +{ + return m_frame ? m_frame->eventHandler()->isHandlingWheelEvent() : false; +} + +bool FrameView::shouldSetCursor() const +{ + Page* page = frame()->page(); + return page && page->isOnscreen() && page->focusController()->isActive(); } bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) @@ -1520,7 +1717,15 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect // Fixed items should always have layers. ASSERT(renderer->hasLayer()); RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); - + +#if USE(ACCELERATED_COMPOSITING) + if (layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForBoundsOutOfView + || layer->viewportConstrainedNotCompositedReason() == RenderLayer::NotCompositedForNoVisibleContent) { + // Don't invalidate for invisible fixed layers. + continue; + } +#endif + #if ENABLE(CSS_FILTERS) if (layer->hasAncestorWithFilterOutsets()) { // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot @@ -1550,9 +1755,8 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect #if USE(ACCELERATED_COMPOSITING) if (isCompositedContentLayer) { updateRect = rootViewToContents(updateRect); - RenderView* root = rootRenderer(this); - ASSERT(root); - root->layer()->setBackingNeedsRepaintInRect(updateRect); + ASSERT(renderView()); + renderView()->layer()->setBackingNeedsRepaintInRect(updateRect); continue; } #endif @@ -1568,17 +1772,18 @@ void FrameView::scrollContentsSlowPath(const IntRect& updateRect) { #if USE(ACCELERATED_COMPOSITING) if (contentsInCompositedLayer()) { - RenderView* root = rootRenderer(this); - ASSERT(root); - IntRect updateRect = visibleContentRect(); // Make sure to "apply" the scale factor here since we're converting from frame view // coordinates to layer backing coordinates. updateRect.scale(1 / m_frame->frameScaleFactor()); - root->layer()->setBackingNeedsRepaintInRect(updateRect); + ASSERT(renderView()); + renderView()->layer()->setBackingNeedsRepaintInRect(updateRect); } + + repaintSlowRepaintObjects(); + if (RenderPart* frameRenderer = m_frame->ownerRenderer()) { if (isEnclosedInCompositingLayer()) { LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(), @@ -1593,6 +1798,20 @@ void FrameView::scrollContentsSlowPath(const IntRect& updateRect) ScrollView::scrollContentsSlowPath(updateRect); } +void FrameView::repaintSlowRepaintObjects() +{ + if (!m_slowRepaintObjects) + return; + + // Renderers with fixed backgrounds may be in compositing layers, so we need to explicitly + // repaint them after scrolling. + RenderObjectSet::const_iterator end = m_slowRepaintObjects->end(); + for (RenderObjectSet::const_iterator it = m_slowRepaintObjects->begin(); it != end; ++it) { + RenderObject* renderer = *it; + renderer->repaint(); + } +} + // Note that this gets called at painting time. void FrameView::setIsOverlapped(bool isOverlapped) { @@ -1687,26 +1906,31 @@ bool FrameView::scrollToAnchor(const String& name) m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); - Element* anchorNode = m_frame->document()->findAnchor(name); + Element* anchorElement = m_frame->document()->findAnchor(name); // Setting to null will clear the current target. - m_frame->document()->setCSSTarget(anchorNode); + m_frame->document()->setCSSTarget(anchorElement); #if ENABLE(SVG) if (m_frame->document()->isSVGDocument()) { - if (SVGSVGElement* svg = static_cast<SVGDocument*>(m_frame->document())->rootElement()) { - svg->setupInitialView(name, anchorNode); - if (!anchorNode) + if (SVGSVGElement* svg = toSVGDocument(m_frame->document())->rootElement()) { + svg->setupInitialView(name, anchorElement); + if (!anchorElement) return true; } } #endif // Implement the rule that "" and "top" both mean top of page as in other browsers. - if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) + if (!anchorElement && !(name.isEmpty() || equalIgnoringCase(name, "top"))) return false; - maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document()); + maintainScrollPositionAtAnchor(anchorElement ? static_cast<Node*>(anchorElement) : m_frame->document()); + + // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation. + if (anchorElement && anchorElement->isFocusable()) + m_frame->document()->setFocusedElement(anchorElement); + return true; } @@ -1720,8 +1944,8 @@ void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) // really mess things up if an anchor scroll comes at a bad moment. m_frame->document()->updateStyleIfNeeded(); // Only do a layout if changes have occurred that make it necessary. - RenderView* root = rootRenderer(this); - if (root && root->needsLayout()) + RenderView* renderView = this->renderView(); + if (renderView && renderView->needsLayout()) layout(); else scrollToAnchor(); @@ -1741,10 +1965,6 @@ void FrameView::setScrollPosition(const IntPoint& scrollPoint) { TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true); m_maintainScrollPositionAnchor = 0; - - if (requestScrollPositionUpdate(scrollPoint)) - return; - ScrollView::setScrollPosition(scrollPoint); } @@ -1770,6 +1990,7 @@ void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect) IntSize offset = scrollOffset(); ScrollView::setFixedVisibleContentRect(visibleContentRect); if (offset != scrollOffset()) { + repaintFixedElementsAfterScrolling(); if (m_frame->page()->settings()->acceleratedCompositingForFixedPositionEnabled()) updateFixedElementsAfterScrolling(); scrollAnimator()->setCurrentPosition(scrollPosition()); @@ -1794,11 +2015,11 @@ void FrameView::setViewportConstrainedObjectsNeedLayout() } } - void FrameView::scrollPositionChangedViaPlatformWidget() { repaintFixedElementsAfterScrolling(); updateFixedElementsAfterScrolling(); + repaintSlowRepaintObjects(); scrollPositionChanged(); } @@ -1808,21 +2029,22 @@ void FrameView::scrollPositionChanged() frame()->eventHandler()->dispatchFakeMouseMoveEventSoon(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidScroll(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidScroll(); } #endif } +// FIXME: this function is misnamed; its primary purpose is to update RenderLayer positions. void FrameView::repaintFixedElementsAfterScrolling() { // For fixed position elements, update widget positions and compositing layers after scrolling, // but only if we're not inside of layout. - if (!m_nestedLayoutCount && hasViewportConstrainedObjects()) { - if (RenderView* root = rootRenderer(this)) { - root->updateWidgetPositions(); - root->layer()->updateLayerPositionsAfterDocumentScroll(); + if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { + if (RenderView* renderView = this->renderView()) { + renderView->updateWidgetPositions(); + renderView->layer()->updateLayerPositionsAfterDocumentScroll(); } } } @@ -1863,8 +2085,8 @@ void FrameView::updateFixedElementsAfterScrolling() return; if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) { - if (RenderView* root = rootRenderer(this)) - root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); + if (RenderView* renderView = this->renderView()) + renderView->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); } #endif } @@ -1874,12 +2096,40 @@ bool FrameView::shouldRubberBandInDirection(ScrollDirection direction) const Page* page = frame() ? frame()->page() : 0; if (!page) return ScrollView::shouldRubberBandInDirection(direction); - return page->chrome()->client()->shouldRubberBandInDirection(direction); + return page->chrome().client()->shouldRubberBandInDirection(direction); +} + +bool FrameView::isRubberBandInProgress() const +{ + if (scrollbarsSuppressed()) + return false; + + // If the scrolling thread updates the scroll position for this FrameView, then we should return + // ScrollingCoordinator::isRubberBandInProgress(). + if (Page* page = m_frame->page()) { + if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { + if (!scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread()) + return scrollingCoordinator->isRubberBandInProgress(); + } + } + + // If the main thread updates the scroll position for this FrameView, we should return + // ScrollAnimator::isRubberBandInProgress(). + if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) + return scrollAnimator->isRubberBandInProgress(); + + return false; } bool FrameView::requestScrollPositionUpdate(const IntPoint& position) { #if ENABLE(THREADED_SCROLLING) + if (TiledBacking* tiledBacking = this->tiledBacking()) { + IntRect visibleRect = visibleContentRect(); + visibleRect.setLocation(position); + tiledBacking->prepopulateRect(visibleRect); + } + if (Page* page = m_frame->page()) { if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) return scrollingCoordinator->requestScrollPositionUpdate(this, position); @@ -1896,7 +2146,7 @@ HostWindow* FrameView::hostWindow() const Page* page = frame() ? frame()->page() : 0; if (!page) return 0; - return page->chrome(); + return &page->chrome(); } const unsigned cRepaintRectUnionThreshold = 25; @@ -1955,6 +2205,15 @@ void FrameView::contentsResized() setNeedsLayout(); } +void FrameView::fixedLayoutSizeChanged() +{ + // Can be triggered before the view is set, see comment in FrameView::visibleContentsResized(). + // An ASSERT is triggered when a view schedules a layout before being attached to a frame. + if (!frame()->view()) + return; + ScrollView::fixedLayoutSizeChanged(); +} + void FrameView::visibleContentsResized() { // We check to make sure the view is attached to a frame() as this method can @@ -1964,13 +2223,13 @@ void FrameView::visibleContentsResized() if (!frame()->view()) return; - if (needsLayout()) + if (!useFixedLayout() && needsLayout()) layout(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidChangeSize(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidChangeSize(); } #endif } @@ -2100,6 +2359,10 @@ void FrameView::resetDeferredRepaintDelay() if (!m_deferringRepaints) doDeferredRepaints(); } +#if USE(ACCELERATED_COMPOSITING) + if (RenderView* view = renderView()) + view->compositor()->disableLayerFlushThrottlingTemporarilyForInteraction(); +#endif } double FrameView::adjustedDeferredRepaintDelay() const @@ -2127,6 +2390,26 @@ void FrameView::endDisableRepaints() m_disableRepaints--; } +void FrameView::updateLayerFlushThrottlingInAllFrames() +{ +#if USE(ACCELERATED_COMPOSITING) + bool isMainLoadProgressing = m_frame->page()->progress()->isMainLoadProgressing(); + for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) { + if (RenderView* renderView = frame->contentRenderer()) + renderView->compositor()->setLayerFlushThrottlingEnabled(isMainLoadProgressing); + } +#endif +} + +void FrameView::adjustTiledBackingCoverage() +{ +#if USE(ACCELERATED_COMPOSITING) + RenderView* renderView = this->renderView(); + if (renderView && renderView->layer()->backing()) + renderView->layer()->backing()->adjustTiledBackingCoverage(); +#endif +} + void FrameView::layoutTimerFired(Timer<FrameView>*) { #ifdef INSTRUMENT_LAYOUT_SCHEDULING @@ -2187,8 +2470,8 @@ void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) { ASSERT(m_frame->view() == this); - RenderView* root = rootRenderer(this); - if (root && root->needsLayout()) { + RenderView* renderView = this->renderView(); + if (renderView && renderView->needsLayout()) { if (relayoutRoot) relayoutRoot->markContainingBlocksForLayout(false); return; @@ -2238,9 +2521,9 @@ bool FrameView::needsLayout() const if (!m_frame) return false; - RenderView* root = rootRenderer(this); + RenderView* renderView = this->renderView(); return layoutPending() - || (root && root->needsLayout()) + || (renderView && renderView->needsLayout()) || m_layoutRoot || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred); } @@ -2252,8 +2535,8 @@ void FrameView::setNeedsLayout() return; } - if (RenderView* root = rootRenderer(this)) - root->setNeedsLayout(true); + if (RenderView* renderView = this->renderView()) + renderView->setNeedsLayout(true); } void FrameView::unscheduleRelayout() @@ -2297,6 +2580,11 @@ void FrameView::setTransparent(bool isTransparent) m_isTransparent = isTransparent; } +bool FrameView::hasOpaqueBackground() const +{ + return !m_isTransparent && !m_baseBackgroundColor.hasAlpha(); +} + Color FrameView::baseBackgroundColor() const { return m_baseBackgroundColor; @@ -2371,45 +2659,60 @@ void FrameView::scrollToAnchor() // Align to the top and to the closest side (this matches other browsers). anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); - if (AXObjectCache::accessibilityEnabled()) - m_frame->document()->axObjectCache()->handleScrolledToAnchor(anchorNode.get()); + if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) + cache->handleScrolledToAnchor(anchorNode.get()); // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor. m_maintainScrollPositionAnchor = anchorNode; } -void FrameView::updateWidget(RenderEmbeddedObject* object) +void FrameView::updateWidget(RenderObject* object) { ASSERT(!object->node() || object->node()->isElementNode()); - Element* ownerElement = static_cast<Element*>(object->node()); + Element* ownerElement = toElement(object->node()); // The object may have already been destroyed (thus node cleared), // but FrameView holds a manual ref, so it won't have been deleted. ASSERT(m_widgetUpdateSet->contains(object)); if (!ownerElement) return; - // No need to update if it's already crashed or known to be missing. - if (object->showsUnavailablePluginIndicator()) - return; + if (object->isEmbeddedObject()) { + RenderEmbeddedObject* embeddedObject = static_cast<RenderEmbeddedObject*>(object); + // No need to update if it's already crashed or known to be missing. + if (embeddedObject->isPluginUnavailable()) + return; - // FIXME: This could turn into a real virtual dispatch if we defined - // updateWidget(PluginCreationOption) on HTMLElement. - if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag) || ownerElement->hasTagName(appletTag)) { - HTMLPlugInImageElement* pluginElement = static_cast<HTMLPlugInImageElement*>(ownerElement); - if (pluginElement->needsWidgetUpdate()) - pluginElement->updateWidget(CreateAnyWidgetType); - } - // FIXME: It is not clear that Media elements need or want this updateWidget() call. + if (object->isSnapshottedPlugIn()) { + if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag)) { + HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(ownerElement); + pluginElement->checkSnapshotStatus(); + } + return; + } + + // FIXME: This could turn into a real virtual dispatch if we defined + // updateWidget(PluginCreationOption) on HTMLElement. + if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag) || ownerElement->hasTagName(appletTag)) { + HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(ownerElement); + if (pluginElement->needsCheckForSizeChange()) { + pluginElement->checkSnapshotStatus(); + return; + } + if (pluginElement->needsWidgetUpdate()) + pluginElement->updateWidget(CreateAnyWidgetType); + } + // FIXME: It is not clear that Media elements need or want this updateWidget() call. #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - else if (ownerElement->isMediaElement()) - static_cast<HTMLMediaElement*>(ownerElement)->updateWidget(CreateAnyWidgetType); + else if (ownerElement->isMediaElement()) + toHTMLMediaElement(ownerElement)->updateWidget(CreateAnyWidgetType); #endif - else - ASSERT_NOT_REACHED(); + else + ASSERT_NOT_REACHED(); - // Caution: it's possible the object was destroyed again, since loading a - // plugin may run any arbitrary javascript. - object->updateWidgetPosition(); + // Caution: it's possible the object was destroyed again, since loading a + // plugin may run any arbitrary JavaScript. + embeddedObject->updateWidgetPosition(); + } } bool FrameView::updateWidgets() @@ -2419,24 +2722,34 @@ bool FrameView::updateWidgets() size_t size = m_widgetUpdateSet->size(); - Vector<RenderEmbeddedObject*> objects; - objects.reserveCapacity(size); - - RenderEmbeddedObjectSet::const_iterator end = m_widgetUpdateSet->end(); - for (RenderEmbeddedObjectSet::const_iterator it = m_widgetUpdateSet->begin(); it != end; ++it) { - objects.uncheckedAppend(*it); - (*it)->ref(); + Vector<RenderObject*> objects; + objects.reserveInitialCapacity(size); + // Protect RendereArena from getting wiped out, when Document is detached during updateWidget(). + RefPtr<RenderArena> protectedArena = m_frame->document()->renderArena(); + + RenderObjectSet::const_iterator end = m_widgetUpdateSet->end(); + for (RenderObjectSet::const_iterator it = m_widgetUpdateSet->begin(); it != end; ++it) { + RenderObject* object = *it; + objects.uncheckedAppend(object); + if (object->isEmbeddedObject()) { + RenderEmbeddedObject* embeddedObject = static_cast<RenderEmbeddedObject*>(object); + embeddedObject->ref(); + } } for (size_t i = 0; i < size; ++i) { - RenderEmbeddedObject* object = objects[i]; + RenderObject* object = objects[i]; updateWidget(object); m_widgetUpdateSet->remove(object); } - RenderArena* arena = m_frame->document()->renderArena(); - for (size_t i = 0; i < size; ++i) - objects[i]->deref(arena); + for (size_t i = 0; i < size; ++i) { + RenderObject* object = objects[i]; + if (object->isEmbeddedObject()) { + RenderEmbeddedObject* embeddedObject = static_cast<RenderEmbeddedObject*>(object); + embeddedObject->deref(protectedArena.get()); + } + } return m_widgetUpdateSet->isEmpty(); } @@ -2456,46 +2769,50 @@ void FrameView::performPostLayoutTasks() m_frame->selection()->setCaretRectNeedsUpdate(); m_frame->selection()->updateAppearance(); - LayoutMilestones milestonesOfInterest = 0; + LayoutMilestones requestedMilestones = 0; LayoutMilestones milestonesAchieved = 0; Page* page = m_frame->page(); if (page) - milestonesOfInterest = page->layoutMilestones(); + requestedMilestones = page->requestedLayoutMilestones(); - if (m_nestedLayoutCount <= 1) { + if (m_nestedLayoutCount <= 1 && m_frame->document()->documentElement()) { if (m_firstLayoutCallbackPending) { m_firstLayoutCallbackPending = false; m_frame->loader()->didFirstLayout(); - if (milestonesOfInterest & DidFirstLayout) + if (requestedMilestones & DidFirstLayout) milestonesAchieved |= DidFirstLayout; if (page) { if (page->mainFrame() == m_frame) page->startCountingRelevantRepaintedObjects(); } } - - // Ensure that we always send this eventually. - if (!m_frame->document()->parsing() && m_frame->loader()->stateMachine()->committedFirstRealDocumentLoad()) - m_isVisuallyNonEmpty = true; + updateIsVisuallyNonEmpty(); // If the layout was done with pending sheets, we are not in fact visually non-empty yet. if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) { m_firstVisuallyNonEmptyLayoutCallbackPending = false; - if (milestonesOfInterest & DidFirstVisuallyNonEmptyLayout) + if (requestedMilestones & DidFirstVisuallyNonEmptyLayout) milestonesAchieved |= DidFirstVisuallyNonEmptyLayout; } } - m_frame->loader()->didLayout(milestonesAchieved); + if (milestonesAchieved) + m_frame->loader()->didLayout(milestonesAchieved); +#if ENABLE(FONT_LOAD_EVENTS) + if (RuntimeEnabledFeatures::fontLoadEventsEnabled()) + m_frame->document()->fontloader()->didLayout(); +#endif // FIXME: We should consider adding DidLayout as a LayoutMilestone. That would let us merge this // with didLayout(LayoutMilestones). m_frame->loader()->client()->dispatchDidLayout(); - RenderView* root = rootRenderer(this); - if (root) - root->updateWidgetPositions(); + if (RenderView* renderView = this->renderView()) + renderView->updateWidgetPositions(); + // layout() protects FrameView, but it still can get destroyed when updateWidgets() + // is called through the post layout timer. + RefPtr<FrameView> protector(this); for (unsigned i = 0; i < maxUpdateWidgetsIterations; i++) { if (updateWidgets()) break; @@ -2507,9 +2824,9 @@ void FrameView::performPostLayoutTasks() } #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - if (root->usesCompositing()) - root->compositor()->frameViewDidLayout(); + if (RenderView* renderView = this->renderView()) { + if (renderView->usesCompositing()) + renderView->compositor()->frameViewDidLayout(); } #endif @@ -2517,31 +2834,61 @@ void FrameView::performPostLayoutTasks() m_actionScheduler->resume(); - if (root && !root->printing()) { - IntSize currentSize; - if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) - currentSize = fixedLayoutSize(); - else - currentSize = visibleContentRect(true /*includeScrollbars*/).size(); - float currentZoomFactor = root->style()->zoom(); - bool resized = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor); - m_lastViewportSize = currentSize; - m_lastZoomFactor = currentZoomFactor; - if (resized) { - m_frame->eventHandler()->sendResizeEvent(); + sendResizeEventIfNeeded(); +} + +void FrameView::sendResizeEventIfNeeded() +{ + ASSERT(m_frame); + + RenderView* renderView = this->renderView(); + if (!renderView || renderView->printing()) + return; + + Page* page = m_frame->page(); + IntSize currentSize; + if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling()) + currentSize = fixedLayoutSize(); + else + currentSize = visibleContentRect(IncludeScrollbars).size(); + + float currentZoomFactor = renderView->style()->zoom(); + bool shouldSendResizeEvent = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor); + + m_lastViewportSize = currentSize; + m_lastZoomFactor = currentZoomFactor; + + if (!shouldSendResizeEvent) + return; + + bool isMainFrame = page && page->mainFrame() == m_frame; + bool canSendResizeEventSynchronously = isMainFrame && !isInLayout(); + + // If we resized during layout, queue up a resize event for later, otherwise fire it right away. + RefPtr<Event> resizeEvent = Event::create(eventNames().resizeEvent, false, false); + if (canSendResizeEventSynchronously) + m_frame->document()->dispatchWindowEvent(resizeEvent.release(), m_frame->document()->domWindow()); + else + m_frame->document()->enqueueWindowEvent(resizeEvent.release()); #if ENABLE(INSPECTOR) - if (InspectorInstrumentation::hasFrontends()) { - if (page) { - if (page->mainFrame() == m_frame) { - if (InspectorClient* inspectorClient = page->inspectorController()->inspectorClient()) - inspectorClient->didResizeMainFrame(m_frame.get()); - } - } - } -#endif - } + if (InspectorInstrumentation::hasFrontends() && isMainFrame) { + if (InspectorClient* inspectorClient = page ? page->inspectorController()->inspectorClient() : 0) + inspectorClient->didResizeMainFrame(m_frame.get()); } +#endif +} + +void FrameView::willStartLiveResize() +{ + ScrollView::willStartLiveResize(); + adjustTiledBackingCoverage(); +} + +void FrameView::willEndLiveResize() +{ + ScrollView::willEndLiveResize(); + adjustTiledBackingCoverage(); } void FrameView::postLayoutTimerFired(Timer<FrameView>*) @@ -2568,14 +2915,8 @@ void FrameView::autoSizeIfEnabled() if (!documentView || !documentElement) return; - RenderBox* documentRenderBox = documentElement->renderBox(); - if (!documentRenderBox) - return; - - // If this is the first time we run autosize, start from small height and - // allow it to grow. - if (!m_didRunAutosize) - resize(frameRect().width(), m_minAutoSize.height()); + // Start from the minimum size and allow it to grow. + resize(m_minAutoSize.width(), m_minAutoSize.height()); IntSize size = frameRect().size(); @@ -2585,7 +2926,7 @@ void FrameView::autoSizeIfEnabled() // Update various sizes including contentsSize, scrollHeight, etc. document->updateLayoutIgnorePendingStylesheets(); int width = documentView->minPreferredLogicalWidth(); - int height = documentRenderBox->scrollHeight(); + int height = documentView->documentRect().height(); IntSize newSize(width, height); // Check to see if a scrollbar is needed for a given dimension and @@ -2701,10 +3042,10 @@ IntRect FrameView::windowClipRect(bool clipToContents) const ASSERT(m_frame->view() == this); if (paintsEntireContents()) - return IntRect(IntPoint(), contentsSize()); + return IntRect(IntPoint(), totalContentsSize()); // Set our clip rect to be our contents. - IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents)); + IntRect clipRect = contentsToWindow(visibleContentRect(clipToContents ? ExcludeScrollbars : IncludeScrollbars)); if (!m_frame || !m_frame->ownerElement()) return clipRect; @@ -2771,7 +3112,18 @@ IntRect FrameView::windowResizerRect() const Page* page = frame() ? frame()->page() : 0; if (!page) return IntRect(); - return page->chrome()->windowResizerRect(); + return page->chrome().windowResizerRect(); +} + +float FrameView::visibleContentScaleFactor() const +{ + if (!m_frame || !m_frame->page()) + return 1; + + if (!m_frame->settings()->applyPageScaleFactorInCompositor() || m_frame != m_frame->page()->mainFrame()) + return 1; + + return m_frame->page()->pageScaleFactor(); } void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb) @@ -2781,7 +3133,7 @@ void FrameView::setVisibleScrollerThumbRect(const IntRect& scrollerThumb) return; if (page->mainFrame() != m_frame) return; - page->chrome()->client()->notifyScrollerThumbIsVisibleInRect(scrollerThumb); + page->chrome().client()->notifyScrollerThumbIsVisibleInRect(scrollerThumb); } bool FrameView::scrollbarsCanBeActive() const @@ -2811,45 +3163,55 @@ ScrollableArea* FrameView::enclosingScrollableArea() const IntRect FrameView::scrollableAreaBoundingBox() const { - // FIXME: This isn't correct for transformed frames. We probably need to ask the renderer instead. - return frameRect(); + RenderPart* ownerRenderer = frame()->ownerRenderer(); + if (!ownerRenderer) + return frameRect(); + + return ownerRenderer->absoluteContentQuad().enclosingBoundingBox(); } -void FrameView::updateScrollableAreaSet() +bool FrameView::isScrollable() { - // That ensures that only inner frames are cached. - if (!parentFrameView()) - return; - // Check for: - // 1) display:none or visibility:hidden set to self or inherited. - // 2) overflow{-x,-y}: hidden; - // 3) scrolling: no; - - // Covers #1. - HTMLFrameOwnerElement* owner = m_frame->ownerElement(); - if (!owner || !owner->renderer() || !owner->renderer()->visibleToHitTesting()) { - parentFrameView()->removeScrollableArea(this); - return; - } + // 1) If there an actual overflow. + // 2) display:none or visibility:hidden set to self or inherited. + // 3) overflow{-x,-y}: hidden; + // 4) scrolling: no; - IntSize contentSize = contentsSize(); + // Covers #1 + IntSize totalContentsSize = this->totalContentsSize(); IntSize visibleContentSize = visibleContentRect().size(); - if ((contentSize.height() <= visibleContentSize.height() && contentSize.width() <= visibleContentSize.width())) { - parentFrameView()->removeScrollableArea(this); - return; - } + if ((totalContentsSize.height() <= visibleContentSize.height() && totalContentsSize.width() <= visibleContentSize.width())) + return false; - // Cover #2 and #3. + // Covers #2. + HTMLFrameOwnerElement* owner = m_frame->ownerElement(); + if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting())) + return false; + + // Cover #3 and #4. ScrollbarMode horizontalMode; ScrollbarMode verticalMode; calculateScrollbarModesForLayout(horizontalMode, verticalMode, RulesFromWebContentOnly); - if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) { - parentFrameView()->removeScrollableArea(this); + if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff) + return false; + + return true; +} + +void FrameView::updateScrollableAreaSet() +{ + // That ensures that only inner frames are cached. + FrameView* parentFrameView = this->parentFrameView(); + if (!parentFrameView) + return; + + if (!isScrollable()) { + parentFrameView->removeScrollableArea(this); return; } - parentFrameView()->addScrollableArea(this); + parentFrameView->addScrollableArea(this); } bool FrameView::shouldSuspendScrollAnimations() const @@ -2864,7 +3226,7 @@ void FrameView::scrollbarStyleChanged(int newStyle, bool forceUpdate) return; if (page->mainFrame() != m_frame) return; - page->chrome()->client()->recommendedScrollbarStyleDidChange(newStyle); + page->chrome().client()->recommendedScrollbarStyleDidChange(newStyle); if (forceUpdate) ScrollView::scrollbarStyleChanged(newStyle, forceUpdate); @@ -2935,7 +3297,7 @@ void FrameView::updateAnnotatedRegions() Page* page = m_frame->page(); if (!page) return; - page->chrome()->client()->annotatedRegionsChanged(); + page->chrome().client()->annotatedRegionsChanged(); } #endif @@ -2951,7 +3313,7 @@ void FrameView::updateScrollCorner() Element* body = doc ? doc->body() : 0; if (body && body->renderer()) { renderer = body->renderer(); - cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); } if (!cornerStyle) { @@ -2959,20 +3321,20 @@ void FrameView::updateScrollCorner() Element* docElement = doc ? doc->documentElement() : 0; if (docElement && docElement->renderer()) { renderer = docElement->renderer(); - cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); } } if (!cornerStyle) { // If we have an owning iframe/frame element, then it can set the custom scrollbar also. if (RenderPart* renderer = m_frame->ownerRenderer()) - cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style()); } } if (cornerStyle) { if (!m_scrollCorner) - m_scrollCorner = new (renderer->renderArena()) RenderScrollbarPart(renderer->document()); + m_scrollCorner = RenderScrollbarPart::createAnonymous(renderer->document()); m_scrollCorner->setStyle(cornerStyle.release()); invalidateScrollCorner(cornerRect); } else if (m_scrollCorner) { @@ -3060,7 +3422,7 @@ bool FrameView::hasCustomScrollbars() const for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { Widget* widget = current->get(); if (widget->isFrameView()) { - if (static_cast<FrameView*>(widget)->hasCustomScrollbars()) + if (toFrameView(widget)->hasCustomScrollbars()) return true; } else if (widget->isScrollbar()) { Scrollbar* scrollbar = static_cast<Scrollbar*>(widget); @@ -3096,7 +3458,7 @@ bool FrameView::isInChildFrameWithFrameFlattening() const return true; } - if (!m_frame->settings() || !m_frame->settings()->frameFlatteningEnabled()) + if (!frameFlatteningEnabled()) return false; if (m_frame->ownerElement()->hasTagName(frameTag)) @@ -3143,8 +3505,8 @@ void FrameView::updateControlTints() if (!m_frame || m_frame->document()->url().isEmpty()) return; - RenderView* root = rootRenderer(this); - if ((root && root->theme()->supportsControlTints()) || hasCustomScrollbars()) + RenderView* renderView = this->renderView(); + if ((renderView && renderView->theme()->supportsControlTints()) || hasCustomScrollbars()) paintControlTints(); } @@ -3171,7 +3533,10 @@ void FrameView::setWasScrolledByUser(bool wasScrolledByUser) if (m_inProgrammaticScroll) return; m_maintainScrollPositionAnchor = 0; + if (m_wasScrolledByUser == wasScrolledByUser) + return; m_wasScrolledByUser = wasScrolledByUser; + adjustTiledBackingCoverage(); } void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) @@ -3179,8 +3544,6 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (!frame()) return; - InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_frame.get()); - Document* document = m_frame->document(); #ifndef NDEBUG @@ -3202,8 +3565,8 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) p->fillRect(rect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB); #endif - RenderView* root = rootRenderer(this); - if (!root) { + RenderView* renderView = this->renderView(); + if (!renderView) { LOG_ERROR("called FrameView::paint with nil renderer"); return; } @@ -3212,6 +3575,9 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (needsLayout()) return; + if (!p->paintingDisabled()) + InspectorInstrumentation::willPaint(renderView); + bool isTopLevelPainter = !sCurrentPaintTimeStamp; if (isTopLevelPainter) sCurrentPaintTimeStamp = currentTime(); @@ -3246,7 +3612,7 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) // m_nodeToDraw is used to draw only one element (and its descendants) RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; - RenderLayer* rootLayer = root->layer(); + RenderLayer* rootLayer = renderView->layer(); #ifndef NDEBUG RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(rootLayer->renderer()); @@ -3274,7 +3640,11 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (isTopLevelPainter) sCurrentPaintTimeStamp = 0; - InspectorInstrumentation::didPaint(cookie, p, rect); + if (!p->paintingDisabled()) { + InspectorInstrumentation::didPaint(renderView, p, rect); + // FIXME: should probably not fire milestones for snapshot painting. https://bugs.webkit.org/show_bug.cgi?id=117623 + firePaintRelatedMilestones(); + } } void FrameView::setPaintBehavior(PaintBehavior behavior) @@ -3292,6 +3662,7 @@ bool FrameView::isPainting() const return m_isPainting; } +// FIXME: change this to use the subtreePaint terminology. void FrameView::setNodeToDraw(Node* node) { m_nodeToDraw = node; @@ -3343,7 +3714,7 @@ void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& hori Page* page = m_frame->page(); if (page->mainFrame() == m_frame) { - if (page->chrome()->client()->paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect)) + if (page->chrome().client()->paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect)) return; } @@ -3386,6 +3757,41 @@ void FrameView::updateLayoutAndStyleIfNeededRecursive() ASSERT(!needsLayout()); } +bool FrameView::qualifiesAsVisuallyNonEmpty() const +{ + // No content yet. + Element* documentElement = m_frame->document()->documentElement(); + if (!documentElement || !documentElement->renderer()) + return false; + + // Ensure that we always get marked visually non-empty eventually. + if (!m_frame->document()->parsing() && m_frame->loader()->stateMachine()->committedFirstRealDocumentLoad()) + return true; + + // Require the document to grow a bit. + static const int documentHeightThreshold = 200; + if (documentElement->renderBox()->layoutOverflowRect().pixelSnappedHeight() < documentHeightThreshold) + return false; + + // The first few hundred characters rarely contain the interesting content of the page. + if (m_visuallyNonEmptyCharacterCount > visualCharacterThreshold) + return true; + // Use a threshold value to prevent very small amounts of visible content from triggering didFirstVisuallyNonEmptyLayout + if (m_visuallyNonEmptyPixelCount > visualPixelThreshold) + return true; + return false; +} + +void FrameView::updateIsVisuallyNonEmpty() +{ + if (m_isVisuallyNonEmpty) + return; + if (!qualifiesAsVisuallyNonEmpty()) + return; + m_isVisuallyNonEmpty = true; + adjustTiledBackingCoverage(); +} + void FrameView::enableAutoSizeMode(bool enable, const IntSize& minSize, const IntSize& maxSize) { ASSERT(!enable || !minSize.isEmpty()); @@ -3420,23 +3826,23 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS { // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see // the state of things before and after the layout - if (RenderView* root = rootRenderer(this)) { - float pageLogicalWidth = root->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); - float pageLogicalHeight = root->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); + if (RenderView* renderView = this->renderView()) { + float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height(); + float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width(); LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); - root->setLogicalWidth(flooredPageLogicalWidth); - root->setPageLogicalHeight(flooredPageLogicalHeight); - root->setNeedsLayoutAndPrefWidthsRecalc(); + renderView->setLogicalWidth(flooredPageLogicalWidth); + renderView->setPageLogicalHeight(flooredPageLogicalHeight); + renderView->setNeedsLayoutAndPrefWidthsRecalc(); forceLayout(); // If we don't fit in the given page width, we'll lay out again. If we don't fit in the // page width when shrunk, we will lay out at maximum shrink and clip extra content. // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping // implementation should not do this! - bool horizontalWritingMode = root->style()->isHorizontalWritingMode(); - const LayoutRect& documentRect = root->documentRect(); + bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode(); + const LayoutRect& documentRect = renderView->documentRect(); LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height(); if (docLogicalWidth > pageLogicalWidth) { int expectedPageWidth = std::min<float>(documentRect.width(), pageSize.width() * maximumShrinkFactor); @@ -3447,24 +3853,24 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth); flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight); - root->setLogicalWidth(flooredPageLogicalWidth); - root->setPageLogicalHeight(flooredPageLogicalHeight); - root->setNeedsLayoutAndPrefWidthsRecalc(); + renderView->setLogicalWidth(flooredPageLogicalWidth); + renderView->setPageLogicalHeight(flooredPageLogicalHeight); + renderView->setNeedsLayoutAndPrefWidthsRecalc(); forceLayout(); - const LayoutRect& updatedDocumentRect = root->documentRect(); + const LayoutRect& updatedDocumentRect = renderView->documentRect(); LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width(); LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x(); LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY(); LayoutUnit clippedLogicalLeft = 0; - if (!root->style()->isLeftToRightDirection()) + if (!renderView->style()->isLeftToRightDirection()) clippedLogicalLeft = docLogicalRight - pageLogicalWidth; LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight); if (!horizontalWritingMode) overflow = overflow.transposedRect(); - root->clearLayoutOverflow(); - root->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. + renderView->clearLayoutOverflow(); + renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again. } } @@ -3474,28 +3880,31 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/) { - if (RenderView* root = rootRenderer(this)) { - // Use a context with painting disabled. - GraphicsContext context((PlatformGraphicsContext*)0); - root->setTruncatedAt(static_cast<int>(floorf(oldBottom))); - IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), root->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop))); - root->setPrintRect(dirtyRect); - root->layer()->paint(&context, dirtyRect); - *newBottom = root->bestTruncatedAt(); - if (*newBottom == 0) - *newBottom = oldBottom; - root->setPrintRect(IntRect()); - } else + RenderView* renderView = this->renderView(); + if (!renderView) { + *newBottom = oldBottom; + return; + + } + // Use a context with painting disabled. + GraphicsContext context((PlatformGraphicsContext*)0); + renderView->setTruncatedAt(static_cast<int>(floorf(oldBottom))); + IntRect dirtyRect(0, static_cast<int>(floorf(oldTop)), renderView->layoutOverflowRect().maxX(), static_cast<int>(ceilf(oldBottom - oldTop))); + renderView->setPrintRect(dirtyRect); + renderView->layer()->paint(&context, dirtyRect); + *newBottom = renderView->bestTruncatedAt(); + if (!*newBottom) *newBottom = oldBottom; + renderView->setPrintRect(IntRect()); } IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const { - IntRect rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect), SnapOffsetForTransforms).enclosingBoundingBox(); + IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer->localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox())); // Convert from page ("absolute") to FrameView coordinates. if (!delegatesScrolling()) - rect.moveBy(-scrollPosition()); + rect.moveBy(-scrollPosition() + IntPoint(0, headerHeight())); return rect; } @@ -3506,21 +3915,21 @@ IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect // Convert from FrameView coords into page ("absolute") coordinates. if (!delegatesScrolling()) - rect.moveBy(scrollPosition()); + rect.moveBy(scrollPositionRelativeToDocument()); // FIXME: we don't have a way to map an absolute rect down to a local quad, so just // move the rect for now. - rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms | SnapOffsetForTransforms))); + rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), UseTransforms))); return rect; } IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const { - IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms | SnapOffsetForTransforms)); + IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, UseTransforms)); // Convert from page ("absolute") to FrameView coordinates. if (!delegatesScrolling()) - point.moveBy(-scrollPosition()); + point.moveBy(-scrollPosition() + IntPoint(0, headerHeight())); return point; } @@ -3530,16 +3939,16 @@ IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoi // Convert from FrameView coords into page ("absolute") coordinates. if (!delegatesScrolling()) - point += IntSize(scrollX(), scrollY()); + point = point + scrollPositionRelativeToDocument(); - return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms | SnapOffsetForTransforms)); + return roundedIntPoint(renderer->absoluteToLocal(point, UseTransforms)); } IntRect FrameView::convertToContainingView(const IntRect& localRect) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); if (!renderer) @@ -3562,7 +3971,7 @@ IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); @@ -3586,7 +3995,7 @@ IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); @@ -3611,7 +4020,7 @@ IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const { if (const ScrollView* parentScrollView = parent()) { if (parentScrollView->isFrameView()) { - const FrameView* parentView = static_cast<const FrameView*>(parentScrollView); + const FrameView* parentView = toFrameView(parentScrollView); // Get our renderer in the parent view RenderPart* renderer = m_frame->ownerRenderer(); @@ -3660,6 +4069,12 @@ void FrameView::setTracksRepaints(bool trackRepaints) if (trackRepaints == m_isTrackingRepaints) return; + // Force layout to flush out any pending repaints. + if (trackRepaints) { + if (frame() && frame()->document()) + frame()->document()->updateLayout(); + } + #if USE(ACCELERATED_COMPOSITING) for (Frame* frame = m_frame->tree()->top(); frame; frame = frame->tree()->traverseNext()) { if (RenderView* renderView = frame->contentRenderer()) @@ -3675,15 +4090,16 @@ void FrameView::resetTrackedRepaints() { m_trackedRepaintRects.clear(); #if USE(ACCELERATED_COMPOSITING) - if (RenderView* root = rootRenderer(this)) { - RenderLayerCompositor* compositor = root->compositor(); - compositor->resetTrackedRepaintRects(); - } + if (RenderView* renderView = this->renderView()) + renderView->compositor()->resetTrackedRepaintRects(); #endif } String FrameView::trackedRepaintRectsAsText() const { + if (frame() && frame()->document()) + frame()->document()->updateLayout(); + TextStream ts; if (!m_trackedRepaintRects.isEmpty()) { ts << "(repaint rects\n"; @@ -3694,18 +4110,24 @@ String FrameView::trackedRepaintRectsAsText() const return ts.release(); } -void FrameView::addScrollableArea(ScrollableArea* scrollableArea) +bool FrameView::addScrollableArea(ScrollableArea* scrollableArea) { if (!m_scrollableAreas) m_scrollableAreas = adoptPtr(new ScrollableAreaSet); - m_scrollableAreas->add(scrollableArea); + return m_scrollableAreas->add(scrollableArea).isNewEntry; } -void FrameView::removeScrollableArea(ScrollableArea* scrollableArea) +bool FrameView::removeScrollableArea(ScrollableArea* scrollableArea) { if (!m_scrollableAreas) - return; - m_scrollableAreas->remove(scrollableArea); + return false; + + ScrollableAreaSet::iterator it = m_scrollableAreas->find(scrollableArea); + if (it == m_scrollableAreas->end()) + return false; + + m_scrollableAreas->remove(it); + return true; } bool FrameView::containsScrollableArea(ScrollableArea* scrollableArea) const @@ -3718,21 +4140,37 @@ bool FrameView::containsScrollableArea(ScrollableArea* scrollableArea) const void FrameView::removeChild(Widget* widget) { if (widget->isFrameView()) - removeScrollableArea(static_cast<FrameView*>(widget)); + removeScrollableArea(toFrameView(widget)); ScrollView::removeChild(widget); } bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) { + // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views + // should handle wheel events. +#if !ENABLE(RUBBER_BANDING) + if (!isScrollable()) + return false; +#endif + + if (delegatesScrolling()) { + IntSize offset = scrollOffset(); + IntSize newOffset = IntSize(offset.width() - wheelEvent.deltaX(), offset.height() - wheelEvent.deltaY()); + if (offset != newOffset) { + ScrollView::scrollTo(newOffset); + scrollPositionChanged(); + frame()->loader()->client()->didChangeScrollOffset(); + } + return true; + } + // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled. if (!canHaveScrollbars()) return false; -#if !PLATFORM(WX) if (platformWidget()) return false; -#endif #if ENABLE(THREADED_SCROLLING) if (Page* page = m_frame->page()) { @@ -3749,20 +4187,20 @@ bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent) bool FrameView::isVerticalDocument() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return true; - return root->style()->isHorizontalWritingMode(); + return renderView->style()->isHorizontalWritingMode(); } bool FrameView::isFlippedDocument() const { - RenderView* root = rootRenderer(this); - if (!root) + RenderView* renderView = this->renderView(); + if (!renderView) return false; - return root->style()->isFlippedBlocksWritingMode(); + return renderView->style()->isFlippedBlocksWritingMode(); } void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification) @@ -3775,8 +4213,8 @@ void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification) AXObjectCache* FrameView::axObjectCache() const { - if (frame() && frame()->document() && frame()->document()->axObjectCacheExists()) - return frame()->document()->axObjectCache(); + if (frame() && frame()->document()) + return frame()->document()->existingAXObjectCache(); return 0; } @@ -3790,4 +4228,72 @@ void FrameView::setScrollingPerformanceLoggingEnabled(bool flag) #endif } +void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) +{ + ScrollableArea::didAddScrollbar(scrollbar, orientation); + if (AXObjectCache* cache = axObjectCache()) + cache->handleScrollbarUpdate(this); +} + +void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation) +{ + ScrollableArea::willRemoveScrollbar(scrollbar, orientation); + if (AXObjectCache* cache = axObjectCache()) { + cache->remove(scrollbar); + cache->handleScrollbarUpdate(this); + } +} + +void FrameView::addPaintPendingMilestones(LayoutMilestones milestones) +{ + m_milestonesPendingPaint |= milestones; +} + +void FrameView::firePaintRelatedMilestones() +{ + Page* page = m_frame->page(); + if (!page) + return; + + LayoutMilestones milestonesAchieved = 0; + + // Make sure the pending paint milestones have actually been requested before we send them. + if (m_milestonesPendingPaint & DidFirstFlushForHeaderLayer) { + if (page->requestedLayoutMilestones() & DidFirstFlushForHeaderLayer) + milestonesAchieved |= DidFirstFlushForHeaderLayer; + } + + if (m_milestonesPendingPaint & DidFirstPaintAfterSuppressedIncrementalRendering) { + if (page->requestedLayoutMilestones() & DidFirstPaintAfterSuppressedIncrementalRendering) + milestonesAchieved |= DidFirstPaintAfterSuppressedIncrementalRendering; + } + + m_milestonesPendingPaint = 0; + + if (milestonesAchieved) { + if (Frame* frame = page->mainFrame()) + frame->loader()->didLayout(milestonesAchieved); + } +} + +void FrameView::setVisualUpdatesAllowedByClient(bool visualUpdatesAllowed) +{ + if (m_visualUpdatesAllowedByClient == visualUpdatesAllowed) + return; + + m_visualUpdatesAllowedByClient = visualUpdatesAllowed; + + m_frame->document()->setVisualUpdatesAllowedByClient(visualUpdatesAllowed); +} + +void FrameView::setScrollPinningBehavior(ScrollPinningBehavior pinning) +{ + m_scrollPinningBehavior = pinning; + + if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) + scrollingCoordinator->setScrollPinningBehavior(pinning); + + updateScrollbars(scrollOffset()); +} + } // namespace WebCore |