Bug 777194. Part 4: When a scrolled layer's visible region includes pixels that are outside the snapped clip rect, those pixels won't be valid after scrolling. r=mattwoodrow
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 17 Aug 2012 11:39:00 +1200
changeset 107343 f2ef195a022a7dac87e0f0eca2383c422b8bb148
parent 107342 2b2e43e83d0fb836cb5aca91905e5702b5ea7854
child 107344 2e2c7ed818d6f352bbce323909d3a6e0b0b8415d
push id14987
push userrocallahan@mozilla.com
push dateTue, 18 Sep 2012 09:34:32 +0000
treeherdermozilla-inbound@be9f5e549658 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs777194
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 777194. Part 4: When a scrolled layer's visible region includes pixels that are outside the snapped clip rect, those pixels won't be valid after scrolling. r=mattwoodrow
layout/generic/nsGfxScrollFrame.cpp
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1948,37 +1948,56 @@ void nsGfxScrollFrameInner::ScrollVisual
     } else {
       flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
     }
   }
   if (canScrollWithBlitting) {
     MarkActive();
   }
 
-  nsRect invalidateRect, displayport;
+  nsRect invalidateRect, displayPort;
+  bool hasDisplayPort =
+    nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
   if (IsIgnoringViewportClipping()) {
     nsRect visualOverflow = mScrolledFrame->GetVisualOverflowRect();
     invalidateRect.UnionRect(visualOverflow + mScrolledFrame->GetPosition(),
             visualOverflow + aOldScrolledFramePos);
   } else {
-    invalidateRect =
-      (nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ?
-      displayport : mScrollPort;
+    invalidateRect = hasDisplayPort ? displayPort : mScrollPort;
   }
 
   mOuter->InvalidateWithFlags(invalidateRect, flags);
 
   if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) {
     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
     nsRect update =
       GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot);
-    update = update.ConvertAppUnitsRoundOut(
+    nsRect displayRootUpdate = update.ConvertAppUnitsRoundOut(
       mOuter->PresContext()->AppUnitsPerDevPixel(),
       displayRoot->PresContext()->AppUnitsPerDevPixel());
-    InvalidateFixedBackgroundFrames(displayRoot, mScrolledFrame, update);
+    InvalidateFixedBackgroundFrames(displayRoot, mScrolledFrame, displayRootUpdate);
+
+    // Invalidate content that has scrolled into view. Normally, this will
+    // already be invalid, because it shouldn't have been drawn in any layer,
+    // but there can be stray rows/columns of pixels that partially overlapped
+    // the layer's visible region and hence were drawn and added to the layer's
+    // visible region, but these pixels ended up outside the cliprect after
+    // snapping so their contents need to be updated now that new content has
+    // scrolled into the cliprect.
+    nsPoint scrollDelta = mScrolledFrame->GetPosition() - aOldScrolledFramePos;
+    if (!hasDisplayPort) {
+      displayPort = GetScrollPortRect();
+    }
+    nsRect preservedContents = displayPort + scrollDelta;
+    nsRegion invalidate;
+    invalidate.Sub(displayPort, preservedContents);
+    nsRegionRectIterator iter(invalidate);
+    while (const nsRect* r = iter.Next()) {
+      mOuter->InvalidateWithFlags(*r, nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT);
+    }
   }
 }
 
 /**
  * Return an appunit value close to aDesired and between aLower and aUpper
  * such that (aDesired - aCurrent)*aRes/aAppUnitsPerPixel is an integer (or
  * as close as we can get modulo rounding to appunits). If that
  * can't be done, just returns aDesired.