From a646bb591393251eda6d92976a291de3c3cebe11 Mon Sep 17 00:00:00 2001 From: Benjamin Stover Date: Wed, 9 Mar 2011 13:35:27 -0800 Subject: [PATCH] Bug 618975 Followup: bitrot and remove mDisplayport from nsDisplayScrollLayer r=cjones r=tn a=blocking-fennec --- dom/base/nsDOMWindowUtils.cpp | 38 ++++----- layout/base/nsDisplayList.cpp | 41 +++++---- layout/base/nsDisplayList.h | 6 +- layout/base/nsPresShell.cpp | 5 -- layout/generic/nsGfxScrollFrame.cpp | 125 +++++++++++++++------------- layout/generic/nsGfxScrollFrame.h | 10 ++- layout/ipc/RenderFrameParent.cpp | 6 +- 7 files changed, 117 insertions(+), 114 deletions(-) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index f531269c6ed1..a26684a8e87e 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -315,31 +315,27 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx, nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); if (rootScrollFrame) { if (content == rootScrollFrame->GetContent()) { - // We are setting the root displayport. The pres context needs a special - // flag to be set. + // We are setting a root displayport for a document. + // The pres shell needs a special flag set. presShell->SetIgnoreViewportScrolling(PR_TRUE); + + // The root document currently has a widget, but we might end up + // painting content inside the displayport but outside the widget + // bounds. This ensures the document's view honors invalidations + // within the displayport. + nsPresContext* presContext = GetPresContext(); + if (presContext && presContext->IsRoot()) { + nsIFrame* rootFrame = presShell->GetRootFrame(); + nsIView* view = rootFrame->GetView(); + if (view) { + view->SetInvalidationDimensions(&displayport); + } + } } } - // FIXME (Bug 593243 should fix this.) - // - // Invalidated content does not pay any attention to the displayport, so - // invalidating the subdocument's root frame could end up not repainting - // visible content. - // - // For instance, imagine the iframe is located at y=1000. Even though the - // displayport may intersect the iframe's viewport, the visual overflow - // rect of the root content could be (0, 0, 800, 500). Since the dirty region - // does not intersect the visible overflow rect, the display list for the - // iframe will not even be generated. - // - // Here, we find the very top presShell and use its root frame for - // invalidation instead. - // - nsPresContext* rootPresContext = GetPresContext()->GetRootPresContext(); - if (rootPresContext) { - nsIPresShell* rootPresShell = rootPresContext->GetPresShell(); - nsIFrame* rootFrame = rootPresShell->FrameManager()->GetRootFrame(); + if (presShell) { + nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame(); if (rootFrame) { rootFrame->InvalidateWithFlags(rootFrame->GetVisualOverflowRectRelativeToSelf(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 41f9cc199929..3e921437775a 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -153,7 +153,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, ContainerLayer* aRoot, nsRect aVisibleRect, nsRect aViewport, - nsRect aDisplayPort, + nsRect* aDisplayPort, ViewID aScrollId) { nsPresContext* presContext = aForFrame->PresContext(); @@ -164,11 +164,11 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel(); metrics.mViewport = aViewport.ToNearestPixels(auPerDevPixel); - if (aViewport != aDisplayPort) { - metrics.mDisplayPort = aDisplayPort.ToNearestPixels(auPerDevPixel); + if (aDisplayPort) { + metrics.mDisplayPort = aDisplayPort->ToNearestPixels(auPerDevPixel); } - nsIScrollableFrame* scrollableFrame = NULL; + nsIScrollableFrame* scrollableFrame = nsnull; if (aViewportFrame) scrollableFrame = aViewportFrame->GetScrollTargetFrame(); @@ -525,17 +525,17 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, : FrameMetrics::NULL_SCROLL_ID; nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); - nsRect visibleRect = mVisibleRect; + nsRect displayport; + bool usingDisplayport = false; if (rootScrollFrame) { nsIContent* content = rootScrollFrame->GetContent(); if (content) { - // If there is a displayport defined for the root content element, - // it will be stored in visibleRect. - nsLayoutUtils::GetDisplayPort(content, &visibleRect); + usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport); } } - RecordFrameMetrics(aForFrame, presShell->GetRootScrollFrame(), - root, mVisibleRect, mVisibleRect, visibleRect, id); + RecordFrameMetrics(aForFrame, rootScrollFrame, + root, mVisibleRect, mVisibleRect, + (usingDisplayport ? &displayport : nsnull), id); // If the layer manager supports resolution scaling, set that up if (LayerManager::LAYERS_BASIC == layerManager->GetBackendType()) { @@ -1706,11 +1706,9 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder, nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, nsIFrame* aForFrame, - nsIFrame* aViewportFrame, - const nsRect& aDisplayPort) + nsIFrame* aViewportFrame) : nsDisplayOwnLayer(aBuilder, aForFrame, aList) , mViewportFrame(aViewportFrame) - , mDisplayPort(aDisplayPort) { #ifdef NS_BUILD_REFCNT_LOGGING MOZ_COUNT_CTOR(nsDisplayScrollLayer); @@ -1735,8 +1733,13 @@ nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder, mViewportFrame->GetPosition() + aBuilder->ToReferenceFrame(mViewportFrame); + bool usingDisplayport = false; + nsRect displayport; + if (content) { + usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport); + } RecordFrameMetrics(mFrame, mViewportFrame, layer, mVisibleRect, viewport, - mDisplayPort, scrollId); + (usingDisplayport ? &displayport : nsnull), scrollId); return layer.forget(); } @@ -1748,17 +1751,13 @@ nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder, PRBool& aContainsRootContentDocBG) { nsPresContext* presContext = mFrame->PresContext(); - - nsRect viewport = mViewportFrame->GetRect() - - mViewportFrame->GetPosition() + - aBuilder->ToReferenceFrame(mViewportFrame); - - if (mDisplayPort != viewport) { + nsRect displayport; + if (nsLayoutUtils::GetDisplayPort(mFrame->GetContent(), &displayport)) { // The visible region for the children may be much bigger than the hole we // are viewing the children from, so that the compositor process has enough // content to asynchronously pan while content is being refreshed. - nsRegion childVisibleRegion = mDisplayPort + aBuilder->ToReferenceFrame(mViewportFrame); + nsRegion childVisibleRegion = displayport + aBuilder->ToReferenceFrame(mViewportFrame); nsRect boundedRect; boundedRect.IntersectRect(childVisibleRegion.GetBounds(), mList.GetBounds(aBuilder)); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 0fe4596d55f4..f2644eacd7cb 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1790,12 +1790,9 @@ class nsDisplayScrollLayer : public nsDisplayOwnLayer * @param aForFrame This will determine what the displayport is. It should be * the root content frame of the scrolled area. * @param aViewportFrame The viewport frame you see this content through. - * @param aDisplayPort Overrides the visibility of the child items if it - * is not equal to the visible area. */ nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, - nsIFrame* aForFrame, nsIFrame* aViewportFrame, - const nsRect& aDisplayPort); + nsIFrame* aForFrame, nsIFrame* aViewportFrame); NS_DISPLAY_DECL_NAME("ScrollLayer", TYPE_SCROLL_LAYER) #ifdef NS_BUILD_REFCNT_LOGGING @@ -1819,7 +1816,6 @@ class nsDisplayScrollLayer : public nsDisplayOwnLayer } private: nsIFrame* mViewportFrame; - nsRect mDisplayPort; }; #endif diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index b0c02ea48494..910f7b003b21 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -6046,11 +6046,6 @@ void PresShell::SetRenderingState(const RenderingState& aState) mRenderFlags = aState.mRenderFlags; mXResolution = aState.mXResolution; mYResolution = aState.mYResolution; - - nsIView* rootView; - if (NS_SUCCEEDED(mViewManager->GetRootView(rootView)) && rootView) { - rootView->SetInvalidationDimensions(&mDisplayPort); - } } void PresShell::SynthesizeMouseMove(PRBool aFromScroll) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 9815e533c10e..76ac19361d02 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -195,12 +195,14 @@ nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect, nsRect damage = aDamageRect + nsPoint(aX, aY); // This is the damage rect that we're going to pass up to our parent. nsRect parentDamage; - nsIPresShell* presShell = PresContext()->PresShell(); // If we're using a displayport, we might be displaying an area // different than our scroll port and the damage needs to be // clipped to that instead. - if (mInner.mIsRoot && presShell->UsingDisplayPort()) { - parentDamage.IntersectRect(damage, presShell->GetDisplayPort()); + nsRect displayport; + PRBool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(), + &displayport); + if (usingDisplayport) { + parentDamage.IntersectRect(damage, displayport); } else { parentDamage.IntersectRect(damage, mInner.mScrollPort); } @@ -1112,12 +1114,14 @@ nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect, nsRect damage = aDamageRect + nsPoint(aX, aY); // This is the damage rect that we're going to pass up to our parent. nsRect parentDamage; - nsIPresShell* presShell = PresContext()->PresShell(); // If we're using a displayport, we might be displaying an area // different than our scroll port and the damage needs to be // clipped to that instead. - if (mInner.mIsRoot && presShell->UsingDisplayPort()) { - parentDamage.IntersectRect(damage, presShell->GetDisplayPort()); + nsRect displayport; + PRBool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(), + &displayport); + if (usingDisplayport) { + parentDamage.IntersectRect(damage, displayport); } else { parentDamage.IntersectRect(damage, mInner.mScrollPort); } @@ -1370,33 +1374,36 @@ static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nsnull; nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter, PRBool aIsRoot) - : mHScrollbarBox(nsnull), - mVScrollbarBox(nsnull), - mScrolledFrame(nsnull), - mScrollCornerBox(nsnull), - mResizerBox(nsnull), - mOuter(aOuter), - mAsyncScroll(nsnull), - mDestination(0, 0), - mScrollPosAtLastPaint(0, 0), - mRestorePos(-1, -1), - mLastPos(-1, -1), - mNeverHasVerticalScrollbar(PR_FALSE), - mNeverHasHorizontalScrollbar(PR_FALSE), - mHasVerticalScrollbar(PR_FALSE), - mHasHorizontalScrollbar(PR_FALSE), - mFrameIsUpdatingScrollbar(PR_FALSE), - mDidHistoryRestore(PR_FALSE), - mIsRoot(aIsRoot), - mSupppressScrollbarUpdate(PR_FALSE), - mSkippedScrollbarLayout(PR_FALSE), - mHadNonInitialReflow(PR_FALSE), - mHorizontalOverflow(PR_FALSE), - mVerticalOverflow(PR_FALSE), - mPostedReflowCallback(PR_FALSE), - mMayHaveDirtyFixedChildren(PR_FALSE), - mUpdateScrollbarAttributes(PR_FALSE), - mCollapsedResizer(PR_FALSE) + : mHScrollbarBox(nsnull) + , mVScrollbarBox(nsnull) + , mScrolledFrame(nsnull) + , mScrollCornerBox(nsnull) + , mResizerBox(nsnull) + , mOuter(aOuter) + , mAsyncScroll(nsnull) + , mDestination(0, 0) + , mScrollPosAtLastPaint(0, 0) + , mRestorePos(-1, -1) + , mLastPos(-1, -1) + , mNeverHasVerticalScrollbar(PR_FALSE) + , mNeverHasHorizontalScrollbar(PR_FALSE) + , mHasVerticalScrollbar(PR_FALSE) + , mHasHorizontalScrollbar(PR_FALSE) + , mFrameIsUpdatingScrollbar(PR_FALSE) + , mDidHistoryRestore(PR_FALSE) + , mIsRoot(aIsRoot) + , mSupppressScrollbarUpdate(PR_FALSE) + , mSkippedScrollbarLayout(PR_FALSE) + , mHadNonInitialReflow(PR_FALSE) + , mHorizontalOverflow(PR_FALSE) + , mVerticalOverflow(PR_FALSE) + , mPostedReflowCallback(PR_FALSE) + , mMayHaveDirtyFixedChildren(PR_FALSE) + , mUpdateScrollbarAttributes(PR_FALSE) + , mCollapsedResizer(PR_FALSE) +#ifdef MOZ_IPC + , mShouldBuildLayer(PR_FALSE) +#endif { // lookup if we're allowed to overlap the content from the look&feel object PRBool canOverlap; @@ -1710,7 +1717,13 @@ void nsGfxScrollFrameInner::ScrollVisual() if (canScrollWithBlitting) { MarkActive(); } - mOuter->InvalidateWithFlags(mScrollPort, flags); + + nsRect invalidateRect, displayport; + invalidateRect = + (nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ? + displayport : mScrollPort; + + mOuter->InvalidateWithFlags(invalidateRect, flags); if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) { nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter); @@ -1835,6 +1848,16 @@ nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder* aBuild return rv; } +PRBool +nsGfxScrollFrameInner::ShouldBuildLayer() const +{ +#ifdef MOZ_IPC + return mShouldBuildLayer; +#else + return PR_FALSE; +#endif +} + nsresult nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, @@ -1879,13 +1902,6 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, scrollParts, createLayersForScrollbars); } - nsRect displayport; - PRBool usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), - &displayport); - if (!usingDisplayPort) { - displayport = mScrollPort; - } - // Overflow clipping can never clip frames outside our subtree, so there // is no need to worry about whether we are a moving frame that might clip // non-moving frames. @@ -1897,14 +1913,12 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, // dirty rect here. dirtyRect.IntersectRect(aDirtyRect, mScrollPort); - if (usingDisplayPort) { - dirtyRect = displayport; - } + // Override the dirty rectangle if the displayport has been set. + nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &dirtyRect); nsDisplayListCollection set; nsPresContext* presContext = mOuter->PresContext(); - PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); #ifdef MOZ_IPC // Since making new layers is expensive, only use nsDisplayScrollLayer @@ -1916,34 +1930,25 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, // range of 20 pixels to eliminate many gfx scroll frames from becoming a // layer. // + PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); nsRect scrollRange = GetScrollRange(); - PRBool buildingLayer = + mShouldBuildLayer = (XRE_GetProcessType() == GeckoProcessType_Content && (scrollRange.width >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel) || scrollRange.height >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel))) && (!mIsRoot || !mOuter->PresContext()->IsRootContentDocument()); - -#else - PRBool buildingLayer = false; #endif - if (buildingLayer) { + if (ShouldBuildLayer()) { // Note that using StackingContext breaks z order, so the resulting // rendering can be incorrect for weird edge cases! + nsDisplayList list; rv = mScrolledFrame->BuildDisplayListForStackingContext( - aBuilder, - dirtyRect + mOuter->GetOffsetTo(mScrolledFrame), - set.Content() - ); + aBuilder, dirtyRect + mOuter->GetOffsetTo(mScrolledFrame), &list); nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer( - aBuilder, - set.Content(), - mScrolledFrame, - mOuter, - displayport - ); + aBuilder, &list, mScrolledFrame, mOuter); set.Content()->AppendNewToTop(layerItem); } else { rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set); diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 46f26d34376a..be2caf6483e9 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -87,6 +87,8 @@ class nsGfxScrollFrameInner : public nsIReflowCallback { void PostOverflowEvent(); void Destroy(); + PRBool ShouldBuildLayer() const; + nsresult BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); @@ -237,7 +239,7 @@ class nsGfxScrollFrameInner : public nsIReflowCallback { nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState); PRBool IsLTR() const; PRBool IsScrollbarOnRight() const; - PRBool IsScrollingActive() const { return mScrollingActive; } + PRBool IsScrollingActive() const { return mScrollingActive || ShouldBuildLayer(); } // adjust the scrollbar rectangle aRect to account for any visible resizer. // aHasResizer specifies if there is a content resizer, however this method // will also check if a widget resizer is present as well. @@ -320,6 +322,12 @@ class nsGfxScrollFrameInner : public nsIReflowCallback { PRPackedBool mScrollbarsCanOverlapContent:1; // If true, the resizer is collapsed and not displayed PRPackedBool mCollapsedResizer:1; + +#ifdef MOZ_IPC + // If true, the layer should always be active because we always build a layer. + // Used for asynchronous scrolling. + PRPackedBool mShouldBuildLayer:1; +#endif }; /** diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index 3630eec82618..7a97a022fa23 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -181,7 +181,11 @@ ComputeShadowTreeTransform(nsIFrame* aContainerFrame, aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel); nsIntPoint metricsScrollOffset = aMetrics->mViewportScrollOffset; - if (aRootFrameLoader->AsyncScrollEnabled()) { + if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) { + // Only use asynchronous scrolling if it is enabled and there is a + // displayport defined. It is useful to have a scroll layer that is + // synchronously scrolled for identifying a scroll area before it is + // being actively scrolled. nsIntPoint scrollCompensation( scrollOffset.x * aInverseScaleX - metricsScrollOffset.x * aConfig.mXScale, scrollOffset.y * aInverseScaleY - metricsScrollOffset.y * aConfig.mYScale);