Bug 593243: Clip invalidations to the displayport when one is set. r=tn

This commit is contained in:
Chris Jones 2011-03-11 17:12:11 -06:00
Родитель 38a95f5928
Коммит 7155968a31
6 изменённых файлов: 62 добавлений и 19 удалений

Просмотреть файл

@ -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();

Просмотреть файл

@ -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

Просмотреть файл

@ -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|

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);