зеркало из https://github.com/mozilla/gecko-dev.git
Bug 847287 patch 6 - Set mWinsInCascade for CSS Animations. r=birtles
This is the main patch for the bug; it makes us use the mechanism added in bug 1125455 to avoid sending animations that aren't currently applying to the compositor. Patch 7 is needed to make this code rerun in all the cases where we need to rerun it, though.
This commit is contained in:
Родитель
538784230b
Коммит
a7bdf3d859
|
@ -160,9 +160,12 @@ struct AnimationProperty
|
|||
// then use this to decide whether to apply the style both in the CSS
|
||||
// cascade and for OMTA.
|
||||
//
|
||||
// FIXME (bug 847287): For CSS Animations, which are overridden by
|
||||
// !important rules in the cascade, we actually determine this from
|
||||
// the CSS cascade computations, and then use it for OMTA.
|
||||
// For CSS Animations, which are overridden by !important rules in the
|
||||
// cascade, we actually determine this from the CSS cascade
|
||||
// computations, and then use it for OMTA.
|
||||
// **NOTE**: For CSS animations, we only bother setting mWinsInCascade
|
||||
// accurately for properties that we can animate on the compositor.
|
||||
// For other properties, we make it always be true.
|
||||
bool mWinsInCascade;
|
||||
|
||||
InfallibleTArray<AnimationPropertySegment> mSegments;
|
||||
|
|
|
@ -69,6 +69,9 @@ public:
|
|||
static void Initialize();
|
||||
#endif
|
||||
|
||||
// NOTE: This can return null after Disconnect().
|
||||
nsPresContext* PresContext() const { return mPresContext; }
|
||||
|
||||
/**
|
||||
* Notify the manager that the pres context is going away.
|
||||
*/
|
||||
|
|
|
@ -391,6 +391,8 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
|
|||
newPlayers[newPlayerIdx]->Cancel();
|
||||
}
|
||||
|
||||
UpdateCascadeResults(aStyleContext, collection);
|
||||
|
||||
TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh();
|
||||
UpdateStyleAndEvents(collection, refreshTime,
|
||||
EnsureStyleRule_IsNotThrottled);
|
||||
|
@ -706,6 +708,115 @@ nsAnimationManager::BuildSegment(InfallibleTArray<AnimationPropertySegment>&
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsAnimationManager::UpdateCascadeResults(
|
||||
nsStyleContext* aStyleContext,
|
||||
AnimationPlayerCollection* aElementAnimations)
|
||||
{
|
||||
/*
|
||||
* Figure out which properties we need to examine.
|
||||
*/
|
||||
|
||||
// size of 2 since we only currently have 2 properties we animate on
|
||||
// the compositor
|
||||
nsAutoTArray<nsCSSProperty, 2> propertiesToTrack;
|
||||
|
||||
{
|
||||
nsCSSPropertySet propertiesToTrackAsSet;
|
||||
|
||||
for (size_t playerIdx = aElementAnimations->mPlayers.Length();
|
||||
playerIdx-- != 0; ) {
|
||||
const AnimationPlayer* player = aElementAnimations->mPlayers[playerIdx];
|
||||
const Animation* anim = player->GetSource();
|
||||
if (!anim) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t propIdx = 0, propEnd = anim->Properties().Length();
|
||||
propIdx != propEnd; ++propIdx) {
|
||||
const AnimationProperty& prop = anim->Properties()[propIdx];
|
||||
// We only bother setting mWinsInCascade for properties that we
|
||||
// can animate on the compositor.
|
||||
if (nsCSSProps::PropHasFlags(prop.mProperty,
|
||||
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
|
||||
if (!propertiesToTrackAsSet.HasProperty(prop.mProperty)) {
|
||||
propertiesToTrack.AppendElement(prop.mProperty);
|
||||
propertiesToTrackAsSet.AddProperty(prop.mProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether those properties are set in things that
|
||||
* override animations.
|
||||
*/
|
||||
|
||||
nsCSSPropertySet propertiesOverridden;
|
||||
nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack,
|
||||
aStyleContext,
|
||||
propertiesOverridden);
|
||||
|
||||
/*
|
||||
* Set mWinsInCascade based both on what is overridden at levels
|
||||
* higher than animations and based on one animation overriding
|
||||
* another.
|
||||
*
|
||||
* We iterate from the last animation to the first, just like we do
|
||||
* when calling ComposeStyle from
|
||||
* AnimationPlayerCollection::EnsureStyleRuleFor. Later animations
|
||||
* override earlier ones, so we add properties to the set of
|
||||
* overridden properties as we encounter them, if the animation is
|
||||
* currently in effect.
|
||||
*/
|
||||
|
||||
bool changed = false;
|
||||
for (size_t playerIdx = aElementAnimations->mPlayers.Length();
|
||||
playerIdx-- != 0; ) {
|
||||
AnimationPlayer* player = aElementAnimations->mPlayers[playerIdx];
|
||||
Animation* anim = player->GetSource();
|
||||
if (!anim) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t propIdx = 0, propEnd = anim->Properties().Length();
|
||||
propIdx != propEnd; ++propIdx) {
|
||||
AnimationProperty& prop = anim->Properties()[propIdx];
|
||||
// We only bother setting mWinsInCascade for properties that we
|
||||
// can animate on the compositor.
|
||||
if (nsCSSProps::PropHasFlags(prop.mProperty,
|
||||
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
|
||||
bool newWinsInCascade =
|
||||
!propertiesOverridden.HasProperty(prop.mProperty);
|
||||
if (newWinsInCascade != prop.mWinsInCascade) {
|
||||
changed = true;
|
||||
}
|
||||
prop.mWinsInCascade = newWinsInCascade;
|
||||
|
||||
if (prop.mWinsInCascade && anim->IsInEffect()) {
|
||||
// This animation is in effect right now, so it overrides
|
||||
// earlier animations. (For animations that aren't in effect,
|
||||
// we set mWinsInCascade as though they were, but they don't
|
||||
// suppress animations lower in the cascade.)
|
||||
propertiesOverridden.AddProperty(prop.mProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
nsPresContext* presContext = aElementAnimations->mManager->PresContext();
|
||||
presContext->RestyleManager()->IncrementAnimationGeneration();
|
||||
aElementAnimations->UpdateAnimationGeneration(presContext);
|
||||
aElementAnimations->PostUpdateLayerAnimations();
|
||||
|
||||
// Invalidate our style rule.
|
||||
aElementAnimations->mNeedsRefreshes = true;
|
||||
aElementAnimations->mStyleRuleRefreshTime = TimeStamp();
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
|
|
|
@ -237,6 +237,10 @@ private:
|
|||
mozilla::css::Declaration* aFromDeclaration,
|
||||
float aToKey, nsStyleContext* aToContext);
|
||||
|
||||
static void UpdateCascadeResults(nsStyleContext* aStyleContext,
|
||||
mozilla::AnimationPlayerCollection*
|
||||
aElementAnimations);
|
||||
|
||||
// The guts of DispatchEvents
|
||||
void DoDispatchEvents();
|
||||
|
||||
|
|
|
@ -685,7 +685,9 @@ nsTransitionManager::UpdateCascadeResults(
|
|||
}
|
||||
|
||||
if (changed) {
|
||||
mPresContext->RestyleManager()->IncrementAnimationGeneration();
|
||||
aTransitions->UpdateAnimationGeneration(mPresContext);
|
||||
aTransitions->PostUpdateLayerAnimations();
|
||||
|
||||
// Invalidate our style rule.
|
||||
aTransitions->mStyleRuleRefreshTime = TimeStamp();
|
||||
|
|
|
@ -430,48 +430,42 @@ addAsyncAnimTest(function *() {
|
|||
yield waitForPaintsFlushed();
|
||||
omta_is("transform", { tx: 32 }, RunningOn.Compositor,
|
||||
"anim2 + anim1 + anim2, translate at 2s");
|
||||
// Bug 980769
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
|
||||
"anim2 + anim1 + anim2, opacity at 2s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
|
||||
"anim2 + anim1 + anim2, opacity at 2s");
|
||||
// drop one of the anim2, and list anim3 as well, which animates
|
||||
// the same property as anim2
|
||||
gDiv.style.animation = "anim1 linear 10s, anim2 linear 20s, anim3 linear 10s";
|
||||
yield waitForPaintsFlushed();
|
||||
omta_is("transform", { tx: 32 }, RunningOn.Compositor,
|
||||
"anim1 + anim2 + anim3, translate at 2s");
|
||||
// Bug 980769
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0",
|
||||
"anim1 + anim2 + anim3, opacity at 2s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0",
|
||||
"anim1 + anim2 + anim3, opacity at 2s");
|
||||
advance_clock(1000);
|
||||
omta_is("transform", { tx: 48 }, RunningOn.Compositor,
|
||||
"anim1 + anim2 + anim3, translate at 3s");
|
||||
// Bug 980769
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
|
||||
"anim1 + anim2 + anim3, opacity at 3s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
|
||||
"anim1 + anim2 + anim3, opacity at 3s");
|
||||
// now swap the anim3 and anim2 order
|
||||
gDiv.style.animation = "anim1 linear 10s, anim3 linear 10s, anim2 linear 20s";
|
||||
yield waitForPaintsFlushed();
|
||||
omta_is("transform", { tx: 48 }, RunningOn.Compositor,
|
||||
"anim1 + anim3 + anim2, translate at 3s");
|
||||
// Bug 980769
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.15",
|
||||
"anim1 + anim3 + anim2, opacity at 3s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.15",
|
||||
"anim1 + anim3 + anim2, opacity at 3s");
|
||||
advance_clock(2000); // (unlike test_animations.html, we seek 2s forwards here
|
||||
// since at 4s anim2 and anim3 produce the same result so
|
||||
// we can't tell which won.)
|
||||
omta_is("transform", { tx: 80 }, RunningOn.Compositor,
|
||||
"anim1 + anim3 + anim2, translate at 5s");
|
||||
// Bug 980769
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.25",
|
||||
"anim1 + anim3 + anim2, opacity at 5s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.25",
|
||||
"anim1 + anim3 + anim2, opacity at 5s");
|
||||
// swap anim3 and anim2 back
|
||||
gDiv.style.animation = "anim1 linear 10s, anim2 linear 20s, anim3 linear 10s";
|
||||
yield waitForPaintsFlushed();
|
||||
omta_is("transform", { tx: 80 }, RunningOn.Compositor,
|
||||
"anim1 + anim2 + anim3, translate at 5s");
|
||||
// Bug 980769
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.3",
|
||||
"anim1 + anim2 + anim3, opacity at 5s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.3",
|
||||
"anim1 + anim2 + anim3, opacity at 5s");
|
||||
// seek past end of anim1
|
||||
advance_clock(5100);
|
||||
yield waitForPaints();
|
||||
|
@ -494,9 +488,8 @@ addAsyncAnimTest(function *() {
|
|||
yield waitForPaintsFlushed();
|
||||
omta_is("transform", { tx: 82 }, RunningOn.Compositor,
|
||||
"anim1 + anim2 + anim3, translate at 11s with fill mode");
|
||||
// Bug 980769 - We should get 0.9 but instead
|
||||
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.9",
|
||||
"anim1 + anim2 + anim3, opacity at 11s");
|
||||
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.9",
|
||||
"anim1 + anim2 + anim3, opacity at 11s");
|
||||
done_div();
|
||||
});
|
||||
|
||||
|
@ -1527,9 +1520,8 @@ addAsyncAnimTest(function *() {
|
|||
new_div("animation: always_fifty 1s linear infinite; " +
|
||||
"transform: translate(200px) ! important;");
|
||||
yield waitForPaintsFlushed();
|
||||
// Bug 847287 - off main thread animations don't cascade correctly
|
||||
omta_todo_is("transform", { tx: 200 }, RunningOn.TodoMainThread,
|
||||
"important author rules override animations");
|
||||
omta_is("transform", { tx: 200 }, RunningOn.MainThread,
|
||||
"important author rules override animations");
|
||||
done_div();
|
||||
});
|
||||
|
||||
|
@ -1721,11 +1713,9 @@ addAsyncAnimTest(function *() {
|
|||
"animation-timing-function: linear; " +
|
||||
"animation-delay: -250ms, -250ms, -750ms, -500ms;");
|
||||
yield waitForPaintsFlushed();
|
||||
// Bug 980769 - off main thread animations incorrectly handle multiple
|
||||
// animations of the same property and element
|
||||
omta_todo_is("opacity", 0.75, RunningOn.Compositor,
|
||||
"animation-name list length is the length that matters, " +
|
||||
"and the last occurrence of a name wins");
|
||||
omta_is("opacity", 0.75, RunningOn.Compositor,
|
||||
"animation-name list length is the length that matters, " +
|
||||
"and the last occurrence of a name wins");
|
||||
omta_is("transform", { ty: 25 }, RunningOn.Compositor,
|
||||
"animation-name list length is the length that matters");
|
||||
done_div();
|
||||
|
@ -2170,41 +2160,44 @@ addAsyncAnimTest(function *() {
|
|||
|
||||
new_div("animation: anim2 1s linear forwards; opacity: 0.5 ! important");
|
||||
yield waitForPaintsFlushed();
|
||||
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
omta_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
"opacity overriding animation at start (0s)");
|
||||
advance_clock(750);
|
||||
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
omta_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
"opacity overriding animation while running (750ms)");
|
||||
advance_clock(1000);
|
||||
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
omta_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
"opacity overriding animation while filling (1750ms)");
|
||||
done_div();
|
||||
|
||||
new_div("animation: anim2 1s linear; opacity: 0.5 ! important");
|
||||
yield waitForPaintsFlushed();
|
||||
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
omta_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
"opacity overriding animation at start (0s)");
|
||||
advance_clock(750);
|
||||
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
omta_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
"opacity overriding animation while running (750ms)");
|
||||
advance_clock(1000);
|
||||
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
omta_is("opacity", 0.5, RunningOn.TodoMainThread,
|
||||
"opacity overriding animation after complete (1750ms)");
|
||||
done_div();
|
||||
|
||||
// One animation overriding another, and then not.
|
||||
new_div("animation: anim2 1s linear, anim3 500ms linear reverse");
|
||||
yield waitForPaintsFlushed();
|
||||
omta_todo_is("opacity", 1, RunningOn.Compositor,
|
||||
omta_is("opacity", 1, RunningOn.Compositor,
|
||||
"anim3 overriding anim2 at start (0s)");
|
||||
advance_clock(400);
|
||||
omta_todo_is("opacity", 0.2, RunningOn.Compositor,
|
||||
omta_is("opacity", 0.2, RunningOn.Compositor,
|
||||
"anim3 overriding anim2 at 400ms");
|
||||
advance_clock(200);
|
||||
// Wait for paints because we're resending animations to the
|
||||
// compositor via an UpdateOpacityLayer hint, which does the resending
|
||||
// via painting.
|
||||
yield waitForPaints();
|
||||
// FIXME: Half of this test fails, which means that omta_todo_is fails
|
||||
// just as much as omta_is. (The value is wrong on both compositor and
|
||||
// main threads.)
|
||||
omta_is("opacity", 0.6, RunningOn.Compositor,
|
||||
"anim2 at 600ms");
|
||||
done_div();
|
||||
|
@ -2220,7 +2213,7 @@ addAsyncAnimTest(function *() {
|
|||
"anim2 at 300ms");
|
||||
gDiv.style.animation = "anim2 1s steps(8, end), anim3 500ms steps(4, end)";
|
||||
yield waitForPaintsFlushed();
|
||||
omta_todo_is("opacity", 0, RunningOn.Compositor,
|
||||
omta_is("opacity", 0, RunningOn.Compositor,
|
||||
"anim3 overriding anim2 at 300ms");
|
||||
advance_clock(475);
|
||||
omta_is("opacity", 0.75, RunningOn.Compositor,
|
||||
|
@ -2230,9 +2223,15 @@ addAsyncAnimTest(function *() {
|
|||
// compositor via an UpdateOpacityLayer hint, which does the resending
|
||||
// via painting.
|
||||
yield waitForPaints();
|
||||
// FIXME: Half of this test fails, which means that omta_todo_is fails
|
||||
// just as much as omta_is. (The value is wrong on both compositor and
|
||||
// main threads.)
|
||||
omta_is("opacity", 0.75, RunningOn.Compositor,
|
||||
"anim2 at 825ms");
|
||||
advance_clock(75);
|
||||
// FIXME: Half of this test fails, which means that omta_todo_is fails
|
||||
// just as much as omta_is. (The value is wrong on both compositor and
|
||||
// main threads.)
|
||||
omta_is("opacity", 0.875, RunningOn.Compositor,
|
||||
"anim2 at 900ms");
|
||||
done_div();
|
||||
|
@ -2248,7 +2247,7 @@ addAsyncAnimTest(function *() {
|
|||
"anim2 at 300ms");
|
||||
gDiv.style.animation = "anim2 1s steps(8, end), anim3 500ms steps(4, end)";
|
||||
yield waitForPaintsFlushed();
|
||||
omta_todo_is("opacity", 0, RunningOn.Compositor,
|
||||
omta_is("opacity", 0, RunningOn.Compositor,
|
||||
"anim3 overriding anim2 at 300ms");
|
||||
advance_clock(475);
|
||||
omta_is("opacity", 0.75, RunningOn.Compositor,
|
||||
|
@ -2260,9 +2259,15 @@ addAsyncAnimTest(function *() {
|
|||
// compositor via an UpdateOpacityLayer hint, which does the resending
|
||||
// via painting.
|
||||
yield waitForPaints();
|
||||
// FIXME: Half of this test fails, which means that omta_todo_is fails
|
||||
// just as much as omta_is. (The value is wrong on both compositor and
|
||||
// main threads.)
|
||||
omta_is("opacity", 0.75, RunningOn.Compositor,
|
||||
"anim2 at 825ms");
|
||||
advance_clock(75);
|
||||
// FIXME: Half of this test fails, which means that omta_todo_is fails
|
||||
// just as much as omta_is. (The value is wrong on both compositor and
|
||||
// main threads.)
|
||||
omta_is("opacity", 0.875, RunningOn.Compositor,
|
||||
"anim2 at 900ms");
|
||||
done_div();
|
||||
|
|
Загрузка…
Ссылка в новой задаче