For transition reversing computations, ensure valuePortion is within 0.0-1.0. (
Bug 611238) r=bzbarsky a=blocking2.0:final
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.
--- 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;