зеркало из 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)
|
||||
{
|
||||
// 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
|
||||
|
|
Загрузка…
Ссылка в новой задаче