gecko-dev/gfx/layers/AnimationInfo.cpp
Kartikaya Gupta 6310cd82fb Bug 1402439 - Redo how we discard compositor animation ids. r=pchang
Instead of always discarding the compositor animation id, and then
sometimes un-discarding it (which involves a linear lookup in nsTArray),
this patch now has the WebRenderLayerManager keep a set of active
animation ids, and uses that to avoid discarding the same animation
twice.

In addition, because the display item can be destroyed at any time (e.g.
in the middle of an animation), we were previously "leaking" compositor
animations in that the compositor side never got notified to discard the
IDs. This resulted in infinite composition loops. This patch solves this
problem by having any unused WebRenderAnimationData trigger discard of
the animation id during destruction. This way, even if the nsDisplayItem
is deleted in the middle of the animation we have a fallback mechanism
to discard the id.

MozReview-Commit-ID: 8G3EYHcg9Kl

--HG--
extra : rebase_source : 45e99a0d71a76a15b7fc7a0d498a6149501a722d
2017-09-22 16:39:57 -04:00

169 lines
3.9 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AnimationInfo.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/AnimationHelper.h"
namespace mozilla {
namespace layers {
AnimationInfo::AnimationInfo(LayerManager* aManager) :
mManager(aManager),
mCompositorAnimationsId(0),
mAnimationGeneration(0),
mMutated(false)
{
}
AnimationInfo::~AnimationInfo()
{
}
void
AnimationInfo::EnsureAnimationsId()
{
if (!mCompositorAnimationsId) {
mCompositorAnimationsId = AnimationHelper::GetNextCompositorAnimationsId();
}
}
Animation*
AnimationInfo::AddAnimation()
{
// Here generates a new id when the first animation is added and
// this id is used to represent the animations in this layer.
EnsureAnimationsId();
MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
Animation* anim = mAnimations.AppendElement();
mMutated = true;
return anim;
}
Animation*
AnimationInfo::AddAnimationForNextTransaction()
{
MOZ_ASSERT(mPendingAnimations,
"should have called ClearAnimationsForNextTransaction first");
Animation* anim = mPendingAnimations->AppendElement();
return anim;
}
void
AnimationInfo::ClearAnimations()
{
mPendingAnimations = nullptr;
if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
return;
}
mAnimations.Clear();
mAnimationData.Clear();
mMutated = true;
}
void
AnimationInfo::ClearAnimationsForNextTransaction()
{
// Ensure we have a non-null mPendingAnimations to mark a future clear.
if (!mPendingAnimations) {
mPendingAnimations = new AnimationArray;
}
mPendingAnimations->Clear();
}
void
AnimationInfo::SetCompositorAnimations(const CompositorAnimations& aCompositorAnimations)
{
mAnimations = aCompositorAnimations.animations();
mCompositorAnimationsId = aCompositorAnimations.id();
mAnimationData.Clear();
AnimationHelper::SetAnimations(mAnimations,
mAnimationData,
mBaseAnimationStyle);
}
bool
AnimationInfo::StartPendingAnimations(const TimeStamp& aReadyTime)
{
bool updated = false;
for (size_t animIdx = 0, animEnd = mAnimations.Length();
animIdx < animEnd; animIdx++) {
Animation& anim = mAnimations[animIdx];
// If the animation is play-pending, resolve the start time.
// This mirrors the calculation in Animation::StartTimeFromReadyTime.
if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
!anim.originTime().IsNull() &&
!anim.isNotPlaying()) {
TimeDuration readyTime = aReadyTime - anim.originTime();
anim.startTime() =
anim.playbackRate() == 0
? readyTime
: readyTime - anim.holdTime().MultDouble(1.0 /
anim.playbackRate());
updated = true;
}
}
return updated;
}
void
AnimationInfo::TransferMutatedFlagToLayer(Layer* aLayer)
{
if (mMutated) {
aLayer->Mutated();
mMutated = false;
}
}
bool
AnimationInfo::ApplyPendingUpdatesForThisTransaction()
{
if (mPendingAnimations) {
mPendingAnimations->SwapElements(mAnimations);
mPendingAnimations = nullptr;
return true;
}
return false;
}
bool
AnimationInfo::HasOpacityAnimation() const
{
for (uint32_t i = 0; i < mAnimations.Length(); i++) {
if (mAnimations[i].property() == eCSSProperty_opacity) {
return true;
}
}
return false;
}
bool
AnimationInfo::HasTransformAnimation() const
{
for (uint32_t i = 0; i < mAnimations.Length(); i++) {
if (mAnimations[i].property() == eCSSProperty_transform) {
return true;
}
}
return false;
}
} // namespace layers
} // namespace mozilla