gecko/dom/animation/PendingPlayerTracker.cpp
Brian Birtles b9e7ffb4b3 Bug 927349 part 15 - Schedule a paint when a new pending animation is added; r=jwatt
We would like to trigger animations from the point when the first frame of the
animation is painted. However, some animations will never trigger a paint (e.g.
animations with an empty keyframes rule). These animations should start start
however. To ensure this, whenever an animation is newly pending we schedule
a paint.
2014-12-22 09:35:41 +09:00

97 lines
2.6 KiB
C++

/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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 "PendingPlayerTracker.h"
#include "mozilla/dom/AnimationTimeline.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
using namespace mozilla;
namespace mozilla {
NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker, mPlayPendingSet, mDocument)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingPlayerTracker, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingPlayerTracker, Release)
void
PendingPlayerTracker::AddPlayPending(dom::AnimationPlayer& aPlayer)
{
mPlayPendingSet.PutEntry(&aPlayer);
// Schedule a paint. Otherwise animations that don't trigger a paint by
// themselves (e.g. CSS animations with an empty keyframes rule) won't
// start until something else paints.
EnsurePaintIsScheduled();
}
void
PendingPlayerTracker::RemovePlayPending(dom::AnimationPlayer& aPlayer)
{
mPlayPendingSet.RemoveEntry(&aPlayer);
}
bool
PendingPlayerTracker::IsWaitingToPlay(dom::AnimationPlayer const& aPlayer) const
{
return mPlayPendingSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer));
}
PLDHashOperator
StartPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
void* aReadyTime)
{
dom::AnimationPlayer* player = aKey->GetKey();
// For animations that are waiting until their first frame has rendered
// before starting, we record the moment when they finish painting
// as the "ready time" and make any pending layer animations start at
// that time.
//
// Here we fast-forward the player's timeline to the same "ready time" and
// then tell the player to start at the timeline's current time.
//
// Redundant calls to FastForward with the same ready time are ignored by
// AnimationTimeline.
dom::AnimationTimeline* timeline = player->Timeline();
timeline->FastForward(*static_cast<const TimeStamp*>(aReadyTime));
player->StartNow();
return PL_DHASH_NEXT;
}
void
PendingPlayerTracker::StartPendingPlayers(const TimeStamp& aReadyTime)
{
mPlayPendingSet.EnumerateEntries(StartPlayerAtTime,
const_cast<TimeStamp*>(&aReadyTime));
mPlayPendingSet.Clear();
}
void
PendingPlayerTracker::EnsurePaintIsScheduled()
{
if (!mDocument) {
return;
}
nsIPresShell* presShell = mDocument->GetShell();
if (!presShell) {
return;
}
nsIFrame* rootFrame = presShell->GetRootFrame();
if (!rootFrame) {
return;
}
rootFrame->SchedulePaint();
}
} // namespace mozilla