diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index e2e0c3157cdd..388f87e938d9 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -6062,21 +6062,11 @@ void PresShell::SetRenderingState(const RenderingState& aState) mXResolution = aState.mXResolution; mYResolution = aState.mYResolution; - // 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. - // + nsIView* rootView; + if (NS_SUCCEEDED(mViewManager->GetRootView(rootView)) && rootView) { + rootView->SetInvalidationDimensions(&mDisplayPort); + } + nsPresContext* rootPresContext = mPresContext->GetRootPresContext(); if (rootPresContext) { nsIPresShell* rootPresShell = rootPresContext->GetPresShell(); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 602db5fdbce9..edd2efe8d477 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -195,7 +195,15 @@ 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; - parentDamage.IntersectRect(damage, mInner.mScrollPort); + 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()); + } else { + parentDamage.IntersectRect(damage, mInner.mScrollPort); + } if (IsScrollingActive()) { // This is the damage rect that we're going to pass up and @@ -1104,7 +1112,15 @@ 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; - parentDamage.IntersectRect(damage, mInner.mScrollPort); + 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()); + } else { + parentDamage.IntersectRect(damage, mInner.mScrollPort); + } if (IsScrollingActive()) { // This is the damage rect that we're going to pass up and diff --git a/view/public/nsIView.h b/view/public/nsIView.h index f9272b66a19a..6357b8e1030f 100644 --- a/view/public/nsIView.h +++ b/view/public/nsIView.h @@ -173,6 +173,17 @@ public: */ nsRect GetBounds() const { return mDimBounds; } + /** + * Set the dimensions at which invalidations are clipped, which can + * be different than |GetDimensions()|. |aRect| is relative to + * |this|. It can be null, in which case invalidations return to + * being clipped to the view dimensions. + * + * The caller is responsible for invalidating the area that may lie + * outside the view dimensions but inside |aRect| after this call. + */ + void SetInvalidationDimensions(const nsRect* aRect); + /** * Get the offset between the coordinate systems of |this| and aOther. * Adding the return value to a point in the coordinate system of |this| diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index a51a88c46fda..bbd417c3a999 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -209,6 +209,7 @@ nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility) mViewManager = aViewManager; mDirtyRegion = nsnull; mDeletionObserver = nsnull; + mHaveInvalidationDimensions = PR_FALSE; mWidgetIsTopLevel = PR_FALSE; } @@ -350,6 +351,11 @@ void nsView::SetPosition(nscoord aX, nscoord aY) ResetWidgetBounds(PR_TRUE, PR_TRUE, PR_FALSE); } +void nsIView::SetInvalidationDimensions(const nsRect* aRect) +{ + return Impl()->SetInvalidationDimensions(aRect); +} + void nsView::SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY) { mDimBounds.x += aX - mPosX; @@ -495,6 +501,13 @@ void nsView::SetDimensions(const nsRect& aRect, PRBool aPaint, PRBool aResizeWid } } +void nsView::SetInvalidationDimensions(const nsRect* aRect) +{ + if ((mHaveInvalidationDimensions = !!aRect)) { + mInvalidationDimensions = *aRect; + } +} + void nsView::NotifyEffectiveVisibilityChanged(PRBool aEffectivelyVisible) { if (!aEffectivelyVisible) diff --git a/view/src/nsView.h b/view/src/nsView.h index e808ee11634a..51c983041d89 100644 --- a/view/src/nsView.h +++ b/view/src/nsView.h @@ -76,6 +76,7 @@ public: */ virtual void SetDimensions(const nsRect &aRect, PRBool aPaint = PR_TRUE, PRBool aResizeWidget = PR_TRUE); + void SetInvalidationDimensions(const nsRect* aRect); void GetDimensions(nsRect &aRect) const { aRect = mDimBounds; aRect.x -= mPosX; aRect.y -= mPosY; } void GetDimensions(nsSize &aSize) const { aSize.width = mDimBounds.width; aSize.height = mDimBounds.height; } @@ -148,6 +149,11 @@ public: nsRect GetDimensions() const { nsRect r = mDimBounds; r.MoveBy(-mPosX, -mPosY); return r; } // Same as GetBounds but converts to parent appunits if they are different. nsRect GetBoundsInParentUnits() const; + + nsRect GetInvalidationDimensions() const { + return mHaveInvalidationDimensions ? mInvalidationDimensions : GetDimensions(); + } + // These are defined exactly the same in nsIView, but for now they have to be redeclared // here because of stupid C++ method hiding rules @@ -202,6 +208,13 @@ protected: void DoResetWidgetBounds(PRBool aMoveOnly, PRBool aInvalidateChangedSize); nsRegion* mDirtyRegion; + // invalidations are clipped to mInvalidationDimensions, not + // GetDimensions(), when mHaveInvalidationDimensions is true. This + // is used to support persistent "displayport" rendering; see + // nsPresShell.cpp. The coordinates of mInvalidationDimensions are + // relative to |this|. + nsRect mInvalidationDimensions; + PRPackedBool mHaveInvalidationDimensions; private: void InitializeWindow(PRBool aEnableDragDrop, PRBool aResetVisibility); diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 79ed1dacc516..91e018bd84f1 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -571,7 +571,7 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget, // If the bounds don't overlap at all, there's nothing to do nsRegion intersection; - intersection.And(aWidgetView->GetDimensions(), aDamagedRegion); + intersection.And(aWidgetView->GetInvalidationDimensions(), aDamagedRegion); if (intersection.IsEmpty()) { return; } @@ -1623,7 +1623,7 @@ nsIntRect nsViewManager::ViewToWidget(nsView *aView, const nsRect &aRect) const NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager"); // intersect aRect with bounds of aView, to prevent generating any illegal rectangles. - nsRect bounds = aView->GetDimensions(); + nsRect bounds = aView->GetInvalidationDimensions(); nsRect rect; rect.IntersectRect(aRect, bounds);