зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
1baff00980
Коммит
ea914b4555
|
@ -489,17 +489,15 @@ void nsScrollPortView::Scroll(nsView *aScrolledView, nsPoint aTwipsDelta, nsPoin
|
||||||
{
|
{
|
||||||
if (aTwipsDelta.x != 0 || aTwipsDelta.y != 0)
|
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();
|
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)
|
if (!scrollWidget)
|
||||||
{
|
{
|
||||||
nsPoint offsetToWidget;
|
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
|
// We should call this after fixing up the widget positions to be
|
||||||
// consistent with the view hierarchy.
|
// consistent with the view hierarchy.
|
||||||
mViewManager->UpdateView(this, 0);
|
mViewManager->UpdateView(this, 0);
|
||||||
} else if (CannotBitBlt(aScrolledView)) {
|
} else if (!canBitBlit) {
|
||||||
// We can't blit for some reason.
|
// We can't blit for some reason.
|
||||||
// Just update the view and adjust widgets
|
// Just update the view and adjust widgets
|
||||||
// Recall that our widget's origin is at our bounds' top-left
|
// 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);
|
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.
|
// Invalidate all widgets which overlap the view, other than the view's own widgets.
|
||||||
void
|
void
|
||||||
|
|
|
@ -451,6 +451,13 @@ public: // NOT in nsIViewManager, so private to the view module
|
||||||
|
|
||||||
nsEventStatus HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured);
|
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.
|
* Called to inform the view manager that a view has scrolled.
|
||||||
* The view manager will invalidate any widgets which may need
|
* The view manager will invalidate any widgets which may need
|
||||||
|
|
Загрузка…
Ссылка в новой задаче