For transition reversing computations, ensure valuePortion is within 0.0-1.0. (Bug 611238) r=bzbarsky a=blocking2.0:final
authorL. David Baron <dbaron@dbaron.org>
Thu, 16 Dec 2010 08:53:17 -0800
changeset 59406 3b4f3b897999b589a75ac621825a8f962eaa54ec
parent 59405 d0e5fb03bae2aabc4475eea791c41e51242a4fa7
child 59407 926d09edbd141a4ae4bc3109211f6702f3464e9f
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbzbarsky, blocking2
bugs611238
milestone2.0b9pre
For transition reversing computations, ensure valuePortion is within 0.0-1.0. (Bug 611238) r=bzbarsky a=blocking2.0:final Without the change to ensure that valuePortion is nonnegative, duration might become negative, which it's not allowed to be. Without this change, this can happen when a transition starts off moving into negative value space, which happens when y1 in the timing function is negative. The result that we want should come from using the absolute value (rather than clamping to zero): if we reverse the transition when it's in this negative space, we want the same movement we'd get if it were the same distance into positive value space, just in the opposite direction. Additionally, I'm clamping valuePortion to be at most 1. This affects "bouncy" transitions where the timing function's y2 is greater than one. This is less critical, but ensures the invariant that a transition will never take longer than its specified time, which seems like a good thing to ensure. I believe doing this computation at this stage is preferable to doing it before the multiplication by oldPT.mReversePortion, since we should be clamping the value within the range of the complete transition, not just relative to the most recent reverse.
layout/style/nsTransitionManager.cpp
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -662,16 +662,29 @@ nsTransitionManager::ConsiderStartingTra
     // the timing differently.
     if (!oldPT.IsRemovedSentinel() &&
         oldPT.mStartForReversingTest == pt.mEndValue) {
       // Compute the appropriate negative transition-delay such that right
       // now we'd end up at the current position.
       double valuePortion =
         oldPT.ValuePortionFor(mostRecentRefresh) * oldPT.mReversePortion +
         (1.0 - oldPT.mReversePortion); 
+      // A timing function with negative y1 (or y2!) might make
+      // valuePortion negative.  In this case, we still want to apply our
+      // reversing logic based on relative distances, not make duration
+      // negative.
+      if (valuePortion < 0.0)
+        valuePortion = -valuePortion;
+      // A timing function with y2 (or y1!) greater than one might
+      // advance past its terminal value.  It's probably a good idea to
+      // clamp valuePortion to be at most one to preserve the invariant
+      // that a transition will complete within at most its specified
+      // time.
+      if (valuePortion > 1.0)
+        valuePortion = 1.0;
 
       // Negative delays are essentially part of the transition
       // function, so reduce them along with the duration, but don't
       // reduce positive delays.
       if (delay < 0.0f)
         delay *= valuePortion;
       duration *= valuePortion;