Bug 881022 - Check that the scrollable frame is still alive after each call to UnsetOpacityOnElement for the two scrollbars to avoid crashing. r=roc, a=bajaj
authorStephen Pohl <spohl.mozilla.bugs@gmail.com>
Sun, 09 Jun 2013 20:38:45 -0700
changeset 142893 98321750ea225d0d6f5e80d63fd78959e0d9e175
parent 142892 2d44faad87c6bfe46400e156ead8577ed9ed177b
child 142894 5370b50c3bea60cb0713626b0242dd69a40a45d7
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, bajaj
bugs881022
milestone23.0a2
Bug 881022 - Check that the scrollable frame is still alive after each call to UnsetOpacityOnElement for the two scrollbars to avoid crashing. r=roc, a=bajaj
layout/generic/ScrollbarActivity.cpp
layout/generic/ScrollbarActivity.h
--- a/layout/generic/ScrollbarActivity.cpp
+++ b/layout/generic/ScrollbarActivity.cpp
@@ -35,17 +35,19 @@ ScrollbarActivity::ActivityOccurred()
   ActivityStopped();
 }
 
 void
 ScrollbarActivity::ActivityStarted()
 {
   mNestedActivityCounter++;
   CancelFadeBeginTimer();
-  SetIsFading(false);
+  if (!SetIsFading(false)) {
+    return;
+  }
   UnregisterFromRefreshDriver();
   StartListeningForEvents();
   SetIsActive(true);
 
   NS_ASSERTION(mIsActive, "need to be active during activity");
   NS_ASSERTION(!mIsFading, "must not be fading during activity");
   NS_ASSERTION(!mFadeBeginTimer, "fade begin timer shouldn't be running");
 }
@@ -215,30 +217,34 @@ void
 ScrollbarActivity::BeginFade()
 {
   NS_ASSERTION(mIsActive, "can't begin fade when we're already inactive");
   NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade begin timer cancelled when scrollbar activity started?");
   NS_ASSERTION(!mIsFading, "shouldn't be fading just yet");
 
   CancelFadeBeginTimer();
   mFadeBeginTime = TimeStamp::Now();
-  SetIsFading(true);
+  if (!SetIsFading(true)) {
+    return;
+  }
   RegisterWithRefreshDriver();
 
   NS_ASSERTION(mIsActive, "only fade while scrollbars are visible");
   NS_ASSERTION(mIsFading, "should be fading now");
 }
 
 void
 ScrollbarActivity::EndFade()
 {
   NS_ASSERTION(mIsActive, "still need to be active at this point");
   NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade end timer cancelled when scrollbar activity started?");
 
-  SetIsFading(false);
+  if (!SetIsFading(false)) {
+    return;
+  }
   SetIsActive(false);
   UnregisterFromRefreshDriver();
   StopListeningForEvents();
 
   NS_ASSERTION(!mIsActive, "should have gone inactive after fade end");
   NS_ASSERTION(!mIsFading, "shouldn't be fading anymore");
   NS_ASSERTION(!mFadeBeginTimer, "fade begin timer shouldn't be running");
 }
@@ -335,28 +341,37 @@ UnsetOpacityOnElement(nsIContent* aConte
     inlineStyleContent->GetStyle(getter_AddRefs(decl));
     if (decl) {
       nsAutoString dummy;
       decl->RemoveProperty(NS_LITERAL_STRING("opacity"), dummy);
     }
   }
 }
 
-void
+bool
 ScrollbarActivity::SetIsFading(bool aNewFading)
 {
   if (mIsFading == aNewFading)
-    return;
+    return true;
 
   mIsFading = aNewFading;
   if (!mIsFading) {
     mFadeBeginTime = TimeStamp();
+    // 'this' may be getting destroyed during UnsetOpacityOnElement calls.
+    nsWeakFrame weakFrame((do_QueryFrame(mScrollableFrame)));
     UnsetOpacityOnElement(GetHorizontalScrollbar());
+    if (!weakFrame.IsAlive()) {
+      return false;
+    }
     UnsetOpacityOnElement(GetVerticalScrollbar());
+    if (!weakFrame.IsAlive()) {
+      return false;
+    }
   }
+  return true;
 }
 
 void
 ScrollbarActivity::StartFadeBeginTimer()
 {
   NS_ASSERTION(!mFadeBeginTimer, "timer already alive!");
   mFadeBeginTimer = do_CreateInstance("@mozilla.org/timer;1");
   mFadeBeginTimer->InitWithFuncCallback(FadeBeginTimerFired, this,
--- a/layout/generic/ScrollbarActivity.h
+++ b/layout/generic/ScrollbarActivity.h
@@ -94,17 +94,17 @@ protected:
   bool IsStillFading(TimeStamp aTime);
 
   void HandleEventForScrollbar(const nsAString& aType,
                                nsIContent* aTarget,
                                nsIContent* aScrollbar,
                                bool* aStoredHoverState);
 
   void SetIsActive(bool aNewActive);
-  void SetIsFading(bool aNewFading);
+  bool SetIsFading(bool aNewFading); // returns false if 'this' was destroyed
 
   void BeginFade();
   void EndFade();
 
   void StartFadeBeginTimer();
   void CancelFadeBeginTimer();
   void StartListeningForEvents();
   void StartListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar);