Bug 602892. Part 2: Ensure that a scrollframe is 'inactive' if it can't be scrolled by blitting. r=tnikkel,a=blocking
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 04 Jan 2011 21:46:59 +1300
changeset 59828 2a0d0ed04874772ed05106229c999493944d12c9
parent 59827 e870951c916747c5b724e108705a880201c50c3d
child 59829 e8c4962380891461eb420959b3efd4ffdcfb084b
push id17803
push userrocallahan@mozilla.com
push dateTue, 04 Jan 2011 08:53:57 +0000
treeherdermozilla-central@2a0d0ed04874 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel, blocking
bugs602892
milestone2.0b9pre
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 602892. Part 2: Ensure that a scrollframe is 'inactive' if it can't be scrolled by blitting. r=tnikkel,a=blocking
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/reftests/border-radius/reftest.list
layout/reftests/border-radius/scroll-1-ref.html
layout/reftests/border-radius/scroll-1.html
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1307,18 +1307,17 @@ public:
   ScrollFrameActivityTracker()
     : nsExpirationTracker<nsGfxScrollFrameInner,4>(TIMEOUT_MS) {}
   ~ScrollFrameActivityTracker() {
     AgeAllGenerations();
   }
 
   virtual void NotifyExpired(nsGfxScrollFrameInner *aObject) {
     RemoveObject(aObject);
-    aObject->mScrollingActive = PR_FALSE;
-    aObject->mOuter->InvalidateFrameSubtree();
+    aObject->MarkInactive();
   }
 };
 
 static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nsnull;
 
 nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
                                              PRBool aIsRoot,
                                              PRBool aIsXUL)
@@ -1538,16 +1537,19 @@ CanScrollWithBlitting(nsIFrame* aFrame)
       return PR_FALSE;
     }
 #ifdef MOZ_SVG
     if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
         f->IsFrameOfType(nsIFrame::eSVG)) {
       return PR_FALSE;
     }
 #endif
+    nsIScrollableFrame* sf = do_QueryFrame(f);
+    if (sf && nsLayoutUtils::HasNonZeroCorner(f->GetStyleBorder()->mBorderRadius))
+      return PR_FALSE;
     if (nsLayoutUtils::IsPopup(f))
       break;
   }
   return PR_TRUE;
 }
 
 static void
 InvalidateFixedBackgroundFramesFromList(nsDisplayListBuilder* aBuilder,
@@ -1604,16 +1606,25 @@ PRBool nsGfxScrollFrameInner::IsAlwaysAc
 {
   // The root scrollframe for a non-chrome document which is the direct
   // child of a chrome document is always treated as "active".
   // XXX maybe we should extend this so that IFRAMEs which are fill the
   // entire viewport (like GMail!) are always active
   return mIsRoot && mOuter->PresContext()->IsRootContentDocument();
 }
 
+void nsGfxScrollFrameInner::MarkInactive()
+{
+  if (IsAlwaysActive() || !mScrollingActive)
+    return;
+
+  mScrollingActive = PR_FALSE;
+  mOuter->InvalidateFrameSubtree();
+}
+
 void nsGfxScrollFrameInner::MarkActive()
 {
   if (IsAlwaysActive())
     return;
 
   mScrollingActive = PR_TRUE;
   if (mActivityExpirationState.IsTracked()) {
     gScrollFrameActivityTracker->MarkUsed(this);
@@ -1633,20 +1644,27 @@ void nsGfxScrollFrameInner::ScrollVisual
   }
 
   rootPresContext->RequestUpdatePluginGeometry(mOuter);
 
   AdjustViews(mScrolledFrame);
   // We need to call this after fixing up the view positions
   // to be consistent with the frame hierarchy.
   PRUint32 flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT;
-  if (IsScrollingActive() && CanScrollWithBlitting(mOuter)) {
-    flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
+  PRBool canScrollWithBlitting = CanScrollWithBlitting(mOuter);
+  if (IsScrollingActive()) {
+    if (!canScrollWithBlitting) {
+      MarkInactive();
+    } else {
+      flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
+    }
   }
-  MarkActive();
+  if (canScrollWithBlitting) {
+    MarkActive();
+  }
   mOuter->InvalidateWithFlags(mScrollPort, flags);
 
   if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) {
     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
     nsRect update =
       GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot);
     update = update.ConvertAppUnitsRoundOut(
       mOuter->PresContext()->AppUnitsPerDevPixel(),
@@ -1772,16 +1790,19 @@ nsGfxScrollFrameInner::BuildDisplayList(
                                         const nsRect&           aDirtyRect,
                                         const nsDisplayListSet& aLists)
 {
   nsresult rv = mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aBuilder->IsPaintingToWindow()) {
     mScrollPosAtLastPaint = GetScrollPosition();
+    if (IsScrollingActive() && !CanScrollWithBlitting(mOuter)) {
+      MarkInactive();
+    }
   }
 
   if (aBuilder->GetIgnoreScrollFrame() == mOuter) {
     // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
     // The scrolled frame shouldn't have its own background/border, so we
     // can just pass aLists directly.
     return mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
                                             aDirtyRect, aLists);
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -234,16 +234,17 @@ public:
       return mScrollCornerContent && mScrollCornerContent->Tag() == nsGkAtoms::resizer;
   }
   void LayoutScrollbars(nsBoxLayoutState& aState,
                         const nsRect& aContentArea,
                         const nsRect& aOldScrollArea);
 
   PRBool IsAlwaysActive() const;
   void MarkActive();
+  void MarkInactive();
   nsExpirationState* GetExpirationState() { return &mActivityExpirationState; }
 
   // owning references to the nsIAnonymousContentCreator-built content
   nsCOMPtr<nsIContent> mHScrollbarContent;
   nsCOMPtr<nsIContent> mVScrollbarContent;
   nsCOMPtr<nsIContent> mScrollCornerContent;
 
   nsRevocableEventPtr<ScrollEvent> mScrollEvent;
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -68,8 +68,10 @@ fails-if(cocoaWidget) == intersecting-cl
 
 # test that border-radius is reduced for scrollbars
 == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html
 == scrollbar-clamping-2.html scrollbar-clamping-2-ref.html
 
 # Test for bad corner joins.
 == corner-joins-1.xhtml corner-joins-1-ref.xhtml
 random-if(winWidget) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml
+
+== scroll-1.html scroll-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/scroll-1-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="border-radius:100px; width:300px; height:300px; overflow:hidden; border:1px solid black;">
+  <div style="height:20px; background:blue;"></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/scroll-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+<script>
+function scrollTo(v) {
+  var d = document.getElementById("d");
+  d.scrollTop = v;
+  if (v < 100) {
+    setTimeout(function() { scrollTo(v + 50); }, 400);
+  } else {
+    document.documentElement.removeAttribute("class");
+  }
+}
+</script>
+</head>
+<body onload="scrollTo(0)">
+<div style="border-radius:100px; width:300px; height:300px; overflow:hidden; border:1px solid black;" id="d">
+  <div style="height:1000px;">
+    <div style="margin-top:100px; height:20px; background:blue;"></div>
+  </div>
+</div>
+</body>
+</html>