Note that this patch has a little bit of a belt-and-braces aspect to it.
In each file, either one of the changes should be sufficient, but one of
them prevents us from doing unneeded work and the other one ensures that
we never apply style resulting from transitions and animations even if
somehow we do that work.
Also note that the tests don't actually test anything usefully, since
the reftest harness doesn't currently make the pres context non-dynamic.
(Thus they're marked as failing.) I'm not sure what I should do about
that, though I'm considering just deleting the tests entirely.
Except for the changes in:
layout/generic/nsIFrame.h (part)
layout/style/nsComputedDOMStyle.h (all)
layout/style/nsRuleNode.cpp (part)
layout/style/nsStyleContext.cpp (part)
layout/style/nsStyleContext.h (part)
(see patch 3b in the bug), this patch was written with the sed script:
s/\<GetStyle\(Font\|Color\|List\|Text\|Visibility\|Quotes\|UserInterface\|TableBorder\|SVG\|Background\|Position\|TextReset\|Display\|Content\|UIReset\|Table\|Margin\|Padding\|Border\|Outline\|XUL\|SVGReset\|Column\)\>/Style\1/g
This makes it conform to our convention that getters returning pointers
that can never be null do not begin with "Get".
nsStyleContext's rule node is never null because we require a rule node
in order to construct a style context.
The CalcStyleDifference call is absolutely necessary even if we didn't
need to process the change list, because it causes the new style
context to have cached structs that we might need for a later
comparison. This is important because, as an optimization, we only
compare structs that have been retrieved. This optimization requires
that when we replace a style context, we fetch all the structs on the
new style context that had been fetched on the old style context (which
is normally necessary anyway in order to do comparison so we can process
the changes appropriately).
However, actually processing the change list is also necessary to fix
the bug; it's the actual change from the miniflush that matters here.
Based on dholbert's debugging information, I think it's mostly likely
because we were failing to process the UpdateOverflow hint.
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.