Bug 539356 - Part 19 - Only repaint retained layers after the previous repainted has been drawn to the window. r=roc

This commit is contained in:
Matt Woodrow 2012-06-30 15:06:13 +12:00
parent a5ce331369
commit 150cbb2336
6 changed files with 58 additions and 17 deletions

View File

@ -415,7 +415,8 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
printf("Starting ProcessPendingUpdates\n");
#endif
mViewManagerFlushIsPending = false;
mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
bool skippedFlush = mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
mViewManagerFlushIsPending |= skippedFlush;
#ifdef DEBUG_INVALIDATIONS
printf("Ending ProcessPendingUpdates\n");
#endif

View File

@ -296,8 +296,11 @@ public:
/**
* Flush the accumulated dirty region to the widget and update widget
* geometry.
*
* @param True if a paint was skipped due to throttling and this
* should be called again after a delay.
*/
virtual void ProcessPendingUpdates()=0;
virtual bool ProcessPendingUpdates()=0;
/**
* Just update widget geometry without flushing the dirty region

View File

@ -176,6 +176,8 @@ nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
mDirtyRegion = nsnull;
mDeletionObserver = nsnull;
mWidgetIsTopLevel = false;
mPendingRefresh = false;
mSkippedPaints = 0;
}
void nsView::DropMouseGrabbing()

View File

@ -162,6 +162,13 @@ public:
nsPoint GetOffsetTo(const nsView* aOther, const PRInt32 aAPD) const;
nsIWidget* GetNearestWidget(nsPoint* aOffset, const PRInt32 aAPD) const;
void SetPendingRefresh(bool aPending) { mPendingRefresh = aPending; }
bool PendingRefresh() { return mPendingRefresh; }
void SkippedPaint() { mSkippedPaints++; }
void ClearSkippedPaints() { mSkippedPaints = 0; }
PRUint32 SkippedPaints() { return mSkippedPaints; }
protected:
// Do the actual work of ResetWidgetBounds, unconditionally. Don't
// call this method if we have no widget.
@ -169,6 +176,15 @@ protected:
nsRegion* mDirtyRegion;
// True if the view has invalidate scheduled with the widget
// and is waiting for nsViewManager::Refresh to be called.
bool mPendingRefresh;
// True if a paint event was skipped while mPendingRefresh was
// true, and a new one should be scheduled once we get
// nsViewManager::Refresh called.
PRUint32 mSkippedPaints;
private:
void InitializeWindow(bool aEnableDragDrop, bool aResetVisibility);
};

View File

@ -303,6 +303,11 @@ void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
bool aWillSendDidPaint)
{
NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
aView->SetPendingRefresh(false);
if (aView->SkippedPaints()) {
RootViewManager()->GetPresShell()->ScheduleViewManagerFlush(true);
aView->ClearSkippedPaints();
}
// damageRegion is the damaged area, in twips, relative to the view origin
nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
@ -354,14 +359,14 @@ void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
}
}
void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
bool nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
bool aFlushDirtyRegion)
{
NS_ASSERTION(IsRootVM(), "Updates will be missed");
// Protect against a null-view.
if (!aView) {
return;
return false;
}
if (aView->HasWidget()) {
@ -369,9 +374,10 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
}
// process pending updates in child view.
bool skipped = false;
for (nsView* childView = aView->GetFirstChild(); childView;
childView = childView->GetNextSibling()) {
ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
skipped |= ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
}
// Push out updates after we've processed the children; ensures that
@ -379,18 +385,28 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
if (aFlushDirtyRegion) {
nsIWidget *widget = aView->GetWidget();
if (widget && widget->NeedsPaint()) {
widget->SetNeedsPaint(false);
if (aView->PendingRefresh() && aView->SkippedPaints() < 5) {
aView->SkippedPaint();
skipped = true;
} else {
aView->ClearSkippedPaints();
aView->SetPendingRefresh(false);
widget->SetNeedsPaint(false);
SetPainting(true);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
#endif
nsAutoScriptBlocker scriptBlocker;
mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, false);
nsAutoScriptBlocker scriptBlocker;
mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, false);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT END ----\n");
printf("---- PAINT END ----\n");
#endif
SetPainting(false);
}
}
FlushDirtyRegionToWidget(aView);
}
return skipped;
}
void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
@ -433,7 +449,7 @@ nsViewManager::PostPendingUpdate()
{
nsViewManager* rootVM = RootViewManager();
rootVM->mHasPendingWidgetGeometryChanges = true;
if (rootVM->mPresShell) {
if (rootVM->mPresShell && !rootVM->IsPainting()) {
rootVM->mPresShell->ScheduleViewManagerFlush(nsIFrame::PAINT_COMPOSITE_ONLY);
}
}
@ -516,6 +532,7 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
leftOver.Sub(aDamagedRegion, children);
if (!leftOver.IsEmpty()) {
aWidgetView->SetPendingRefresh(true);
const nsRect* r;
for (nsRegionRectIterator iter(leftOver); (r = iter.Next());) {
nsIntRect bounds = ViewToWidget(aWidgetView, *r);
@ -1302,16 +1319,15 @@ nsViewManager::IsPainting(bool& aIsPainting)
return NS_OK;
}
void
bool
nsViewManager::ProcessPendingUpdates()
{
if (!IsRootVM()) {
RootViewManager()->ProcessPendingUpdates();
return;
return RootViewManager()->ProcessPendingUpdates();
}
mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
ProcessPendingUpdatesForView(mRootView, true);
return ProcessPendingUpdatesForView(mRootView, true);
}
void

View File

@ -105,7 +105,7 @@ public:
/* Update the cached RootViewManager pointer on this view manager. */
void InvalidateHierarchy();
virtual void ProcessPendingUpdates();
virtual bool ProcessPendingUpdates();
virtual void UpdateWidgetGeometry();
protected:
@ -114,7 +114,10 @@ protected:
private:
void FlushPendingInvalidates();
void ProcessPendingUpdatesForView(nsView *aView,
/* Returns true if we skipped painting a view and we should try
* again later.
*/
bool ProcessPendingUpdatesForView(nsView *aView,
bool aFlushDirtyRegion = true);
void FlushDirtyRegionToWidget(nsView* aView);
/**