Fix invalidation regression when scrolling. When we bit-blit, we need to

make copies of existing dirty regions, offset them by the scroll amount, and
add to our dirty region on the scrolling view.  Bug 280041, r+sr=roc
This commit is contained in:
bzbarsky%mit.edu 2005-02-03 05:01:54 +00:00
Родитель bd03314ed7
Коммит cad0d708f5
3 изменённых файлов: 68 добавлений и 11 удалений

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

@ -489,17 +489,15 @@ void nsScrollPortView::Scroll(nsView *aScrolledView, nsPoint aTwipsDelta, nsPoin
{
if (aTwipsDelta.x != 0 || aTwipsDelta.y != 0)
{
// Since we keep track of the dirty region as absolute coordinates,
// we need to offset it by the amount we scrolled.
if (HasNonEmptyDirtyRegion()) {
nsRegion* rgn = GetDirtyRegion();
if (rgn) {
rgn->MoveBy(aTwipsDelta);
}
}
nsIWidget *scrollWidget = GetWidget();
PRBool canBitBlit = scrollWidget && !CannotBitBlt(aScrolledView);
if (canBitBlit) {
// We're going to bit-blit. Let the viewmanager know so it can
// adjust dirty regions appropriately.
mViewManager->WillBitBlit(this, aTwipsDelta);
}
if (!scrollWidget)
{
nsPoint offsetToWidget;
@ -514,7 +512,7 @@ void nsScrollPortView::Scroll(nsView *aScrolledView, nsPoint aTwipsDelta, nsPoin
// We should call this after fixing up the widget positions to be
// consistent with the view hierarchy.
mViewManager->UpdateView(this, 0);
} else if (CannotBitBlt(aScrolledView)) {
} else if (!canBitBlit) {
// We can't blit for some reason.
// Just update the view and adjust widgets
// Recall that our widget's origin is at our bounds' top-left

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

@ -1650,6 +1650,58 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
return UpdateView(view, bounds, aUpdateFlags);
}
// This method accumulates the intersectons of all dirty regions attached to
// descendants of aSourceView with the cliprect of aTargetView into the dirty
// region of aTargetView, after offseting said intersections by aOffset.
static void
AccumulateIntersectionsIntoDirtyRegion(nsView* aTargetView,
nsView* aSourceView,
const nsPoint& aOffset)
{
if (aSourceView->HasNonEmptyDirtyRegion()) {
// In most cases, aSourceView is an ancestor of aTargetView, since most
// commonly we have dirty rects on the root view.
nsPoint offset = aTargetView->GetOffsetTo(aSourceView);
nsRegion intersection;
intersection.And(*aSourceView->GetDirtyRegion(),
aTargetView->GetClippedRect() + offset);
if (!intersection.IsEmpty()) {
nsRegion* targetRegion = aTargetView->GetDirtyRegion();
if (targetRegion) {
intersection.MoveBy(-offset + aOffset);
targetRegion->Or(*targetRegion, intersection);
// Random simplification number...
targetRegion->SimplifyOutward(20);
}
}
}
if (aSourceView == aTargetView) {
// No need to do this with kids of aTargetView
return;
}
for (nsView* kid = aSourceView->GetFirstChild();
kid;
kid = kid->GetNextSibling()) {
AccumulateIntersectionsIntoDirtyRegion(aTargetView, kid, aOffset);
}
}
void
nsViewManager::WillBitBlit(nsView* aView, nsPoint aScrollAmount)
{
if (!IsRootVM()) {
return RootViewManager()->WillBitBlit(aView, aScrollAmount);
}
NS_PRECONDITION(aView, "Must have a view");
NS_PRECONDITION(aView->HasWidget(), "View must have a widget");
// Since the view is actually moving the widget by -aScrollAmount, that's the
// offset we want to use when accumulating dirty rects.
AccumulateIntersectionsIntoDirtyRegion(aView, GetRootView(), -aScrollAmount);
}
// Invalidate all widgets which overlap the view, other than the view's own widgets.
void

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

@ -451,6 +451,13 @@ public: // NOT in nsIViewManager, so private to the view module
nsEventStatus HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured);
/**
* Called to inform the view manager that a view is about to bit-blit.
* @param aView the view that will bit-blit
* @param aScrollAmount how much aView will scroll by
*/
void WillBitBlit(nsView* aView, nsPoint aScrollAmount);
/**
* Called to inform the view manager that a view has scrolled.
* The view manager will invalidate any widgets which may need