2011-04-12 06:18:43 +00:00
|
|
|
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
2012-05-21 11:12:37 +00:00
|
|
|
/* 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/. */
|
2011-04-12 06:18:43 +00:00
|
|
|
|
2013-10-22 20:55:14 +00:00
|
|
|
#include "AnimationCommon.h"
|
2013-10-22 12:14:41 +00:00
|
|
|
#include "nsTransitionManager.h"
|
|
|
|
#include "nsAnimationManager.h"
|
|
|
|
|
2014-06-20 03:39:25 +00:00
|
|
|
#include "ActiveLayerTracker.h"
|
2013-10-22 12:14:41 +00:00
|
|
|
#include "gfxPlatform.h"
|
2011-04-12 06:18:43 +00:00
|
|
|
#include "nsRuleData.h"
|
2014-06-20 03:39:24 +00:00
|
|
|
#include "nsCSSPropertySet.h"
|
2011-04-12 06:18:43 +00:00
|
|
|
#include "nsCSSValue.h"
|
2014-07-16 00:02:30 +00:00
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2015-06-09 02:13:53 +00:00
|
|
|
#include "nsDOMMutationObserver.h"
|
2011-04-12 06:18:43 +00:00
|
|
|
#include "nsStyleContext.h"
|
2012-07-31 17:28:21 +00:00
|
|
|
#include "nsIFrame.h"
|
2012-07-31 17:28:22 +00:00
|
|
|
#include "nsLayoutUtils.h"
|
2012-12-11 21:12:43 +00:00
|
|
|
#include "mozilla/LookAndFeel.h"
|
|
|
|
#include "Layers.h"
|
|
|
|
#include "FrameLayerBuilder.h"
|
|
|
|
#include "nsDisplayList.h"
|
2013-06-23 12:03:39 +00:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2015-04-14 23:48:21 +00:00
|
|
|
#include "mozilla/dom/KeyframeEffect.h"
|
2013-08-19 22:55:18 +00:00
|
|
|
#include "RestyleManager.h"
|
2014-11-20 02:48:41 +00:00
|
|
|
#include "nsRuleProcessorData.h"
|
2013-10-22 12:14:41 +00:00
|
|
|
#include "nsStyleSet.h"
|
|
|
|
#include "nsStyleChangeList.h"
|
|
|
|
|
2014-04-03 05:57:28 +00:00
|
|
|
using mozilla::layers::Layer;
|
2015-04-21 01:22:09 +00:00
|
|
|
using mozilla::dom::Animation;
|
2015-04-30 13:06:43 +00:00
|
|
|
using mozilla::dom::KeyframeEffectReadOnly;
|
2011-04-12 06:18:43 +00:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2012-08-22 01:48:47 +00:00
|
|
|
/* static */ bool
|
|
|
|
IsGeometricProperty(nsCSSProperty aProperty)
|
|
|
|
{
|
|
|
|
switch (aProperty) {
|
|
|
|
case eCSSProperty_bottom:
|
|
|
|
case eCSSProperty_height:
|
|
|
|
case eCSSProperty_left:
|
|
|
|
case eCSSProperty_right:
|
|
|
|
case eCSSProperty_top:
|
|
|
|
case eCSSProperty_width:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-12 06:18:43 +00:00
|
|
|
CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext)
|
|
|
|
: mPresContext(aPresContext)
|
2014-11-17 04:45:56 +00:00
|
|
|
, mIsObservingRefreshDriver(false)
|
2011-04-12 06:18:43 +00:00
|
|
|
{
|
2014-06-26 23:57:13 +00:00
|
|
|
PR_INIT_CLIST(&mElementCollections);
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CommonAnimationManager::~CommonAnimationManager()
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(!mPresContext, "Disconnect should have been called");
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CommonAnimationManager::Disconnect()
|
|
|
|
{
|
|
|
|
// Content nodes might outlive the transition or animation manager.
|
2014-06-26 23:57:13 +00:00
|
|
|
RemoveAllElementCollections();
|
2011-04-12 06:18:43 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
mPresContext = nullptr;
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-17 04:45:56 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
CommonAnimationManager::AddElementCollection(AnimationCollection* aCollection)
|
2014-11-17 04:45:56 +00:00
|
|
|
{
|
|
|
|
if (!mIsObservingRefreshDriver) {
|
|
|
|
NS_ASSERTION(aCollection->mNeedsRefreshes,
|
|
|
|
"Added data which doesn't need refreshing?");
|
|
|
|
// We need to observe the refresh driver.
|
|
|
|
mPresContext->RefreshDriver()->AddRefreshObserver(this, Flush_Style);
|
|
|
|
mIsObservingRefreshDriver = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_INSERT_BEFORE(aCollection, &mElementCollections);
|
|
|
|
}
|
|
|
|
|
2011-04-12 06:18:43 +00:00
|
|
|
void
|
2014-06-26 23:57:13 +00:00
|
|
|
CommonAnimationManager::RemoveAllElementCollections()
|
2011-04-12 06:18:43 +00:00
|
|
|
{
|
2014-06-26 23:57:13 +00:00
|
|
|
while (!PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection* head =
|
|
|
|
static_cast<AnimationCollection*>(PR_LIST_HEAD(&mElementCollections));
|
2011-04-12 06:18:43 +00:00
|
|
|
head->Destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:45:56 +00:00
|
|
|
void
|
2015-03-24 00:06:06 +00:00
|
|
|
CommonAnimationManager::MaybeStartObservingRefreshDriver()
|
|
|
|
{
|
|
|
|
if (mIsObservingRefreshDriver || !NeedsRefresh()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mPresContext->RefreshDriver()->AddRefreshObserver(this, Flush_Style);
|
|
|
|
mIsObservingRefreshDriver = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CommonAnimationManager::MaybeStartOrStopObservingRefreshDriver()
|
|
|
|
{
|
|
|
|
bool needsRefresh = NeedsRefresh();
|
|
|
|
if (needsRefresh && !mIsObservingRefreshDriver) {
|
|
|
|
mPresContext->RefreshDriver()->AddRefreshObserver(this, Flush_Style);
|
|
|
|
} else if (!needsRefresh && mIsObservingRefreshDriver) {
|
|
|
|
mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style);
|
|
|
|
}
|
|
|
|
mIsObservingRefreshDriver = needsRefresh;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CommonAnimationManager::NeedsRefresh() const
|
2014-11-17 04:45:56 +00:00
|
|
|
{
|
|
|
|
for (PRCList *l = PR_LIST_HEAD(&mElementCollections);
|
|
|
|
l != &mElementCollections;
|
|
|
|
l = PR_NEXT_LINK(l)) {
|
2015-04-21 01:22:10 +00:00
|
|
|
if (static_cast<AnimationCollection*>(l)->mNeedsRefreshes) {
|
2015-03-24 00:06:06 +00:00
|
|
|
return true;
|
2014-11-17 04:45:56 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-24 00:06:06 +00:00
|
|
|
return false;
|
2014-11-17 04:45:56 +00:00
|
|
|
}
|
|
|
|
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection*
|
2015-07-01 18:43:13 +00:00
|
|
|
CommonAnimationManager::GetAnimationCollection(const nsIFrame* aFrame)
|
2014-06-20 03:39:25 +00:00
|
|
|
{
|
2015-07-01 18:43:13 +00:00
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
if (!content) {
|
2014-06-20 03:39:25 +00:00
|
|
|
return nullptr;
|
2015-07-01 15:55:51 +00:00
|
|
|
}
|
2015-07-01 18:43:13 +00:00
|
|
|
nsIAtom* animProp;
|
|
|
|
if (aFrame->IsGeneratedContentFrame()) {
|
|
|
|
nsIFrame* parent = aFrame->GetParent();
|
|
|
|
if (parent->IsGeneratedContentFrame()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
nsIAtom* name = content->NodeInfo()->NameAtom();
|
|
|
|
if (name == nsGkAtoms::mozgeneratedcontentbefore) {
|
|
|
|
animProp = GetAnimationsBeforeAtom();
|
|
|
|
} else if (name == nsGkAtoms::mozgeneratedcontentafter) {
|
|
|
|
animProp = GetAnimationsAfterAtom();
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
content = content->GetParent();
|
|
|
|
if (!content) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-07-01 15:55:51 +00:00
|
|
|
} else {
|
2015-07-01 18:43:13 +00:00
|
|
|
if (!content->MayHaveAnimations()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
animProp = GetAnimationsAtom();
|
2015-07-01 15:55:51 +00:00
|
|
|
}
|
2015-04-01 03:23:24 +00:00
|
|
|
|
2015-07-01 18:43:13 +00:00
|
|
|
return static_cast<AnimationCollection*>(content->GetProperty(animProp));
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationCollection*
|
|
|
|
CommonAnimationManager::GetAnimationsForCompositor(const nsIFrame* aFrame,
|
|
|
|
nsCSSProperty aProperty)
|
|
|
|
{
|
|
|
|
AnimationCollection* collection = GetAnimationCollection(aFrame);
|
2014-06-26 23:57:13 +00:00
|
|
|
if (!collection ||
|
Bug 1181392 part 5 - Remove use of IsFinishedTransition from AnimationCollection::HasAnimationOfProperty; r=dbaron
AnimationCollection::HasAnimationOfProperty uses IsFinishedTransition to filter
out transitions that should otherwise be ignored. This is used in the following
places:
1. nsLayoutUtils::HasAnimations
The is only used by nsIFrame::BuildDisplayListForStackingContext to see if
there are any opacity animations
For this case, simply returning *current* animations would be sufficient
(since finished but filling animations should have already filled in the
display opacity)
2. CommonAnimationManager::GetAnimationsForCompositor
This should really only return *current* animations--that is, animations that
are running or scheduled to run. Finished animations never run on the
compositor. Indeed, only *playing* animations run on the compositor but, as
we will see in some of the cases below, it is sometimes useful to know that
an animation *will* run on the compositor in the near future (e.g. so we can
pre-render content).
The places where GetAnimationsForCompositor is used are:
- When building layers to add animations to layers in nsDisplayList--in this
case we skip any animations that aren't playing so if
GetAnimationsForCompositor only returned current animations that would be
more than sufficient.
- In nsLayoutUtils::HasAnimationsForCompositor. This in turn is used:
- In ChooseScaleAndSetTransform to see if the transform is being animated
on the compositor. If so, it calls
nsLayoutUtils::ComputeSuitableScaleForAnimation (which also calls
GetAnimationsForCompositor) and passes the result to
GetMinAndMaxScaleForAnimationProperty which we have already adjusted in
part 4 of this patch series to only deal with *relevant* animations
Relevant animations include both current animations and in effect
animations but we don't run forwards-filling animations on the compositor
so GetAnimationsForCompositor should NOT return them. Current animations
should be enough. In fact, playing animations should be enough but we
might want to pre-render layers at a suitable size during their delay
phase so returning current animations is probably ok.
- In nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay to add a fuzz
factor to the overflow rect for frames undergoing a transform animation
on the compositor. In this case too current animations should be
sufficient.
- In nsDisplayOpacity::NeedsActiveLayer to say "yes" if we are animating
opacity on the compositor. Presumably in this case it would be good to
say "yes" if the animation is in the delay phase too (as it currently
does). After the animation is finished, we should drop the layer, i.e.
current animations should be sufficient.
- In nsDisplayTransform::ShouldPrerenderTransformedContent. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to pre-render
transformed content for animations that are current.
- In nsDisplayTransform::GetLayerState. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to return active here
for current animations.
- In nsIFrame::IsTransformed. Here we test the display style to see if
there is a transform and also check if transform is being animated on the
compositor. As a result, we really only need HasAnimationsForCompositor
to return true for animations that are playing--otherwise the display
style will tell us if we're transformed or not. Returning true for all
current compositor animations (which is a superset of playing), however,
should not cause problems (we already return true for even more than
that).
- In nsIFrame::HasOpacityInternal which is much the same as
nsIFrame::IsTransformed and hence current should be fine.
3. AnimationCollection::CanThrottleAnimation
Here, HasAnimationOfProperty is used when looking for animations that would
disqualify us from throttling the animation by having an out-of-date layer
generation or being a transform animation that affects scroll and so requires
that we do the occasional main thread sample to update scrollbars.
It would seem like current animations are enough here too. One interesting
case is where we *had* a compositor animation but it has finished or been
cancelled. In that case, the animation won't be current and we should not
throttle the animation since we need to take it off its layer.
It turns out checking for current animations is still ok in this case too.
The reasoning is as follows:
- If the animation is newly-finished, we'll pick that up in
Animation::CanThrottle and return false then.
- If the animation is newly-idle then there are two cases:
If the cancelled animation was the only compositor animation then
AnimationCollection::CanPerformOnCompositorThread will notice that there
are no playing compositor animations and return false and
AnimationCollection::CanThrottleAnimation will never be called.
If there are other compositor animations running, then
AnimationCollection::CanThrottleAnimation will still return false because
whatever cancelled the animation will update the animation generation and
we'll notice the mismatch between the layer animation generation and the
animation generation on the collection.
Based on the above analysis it appears that making
AnimationCollection::HasAnimationOfProperty return only current animations (and
simulatneously renaming it to HasCurrentAnimationOfProperty) is safe. Indeed, in
effect, we already do this for transitions but not for animations. This patch
generalizes this behavior to all animations.
This patch also updates test_animations_omta.html since it was incorrectly
testing that a finished opacity animation was still running on the compositor.
Finished animations should not run on the compositor and the changes in this
patch cause that to happen. The reason we don't just update this test to check
for RunningOn.MainThread is that for opacity animations, unlike transform
animations, we can't detect if an opacity on a layer was set by animation or
not. As a result, for opacity animations we typically test the opacity on
either the main thread or compositor in order to allow for the case where an
animation-set opacity is still lingering on the compositor.
2015-08-07 03:29:36 +00:00
|
|
|
!collection->HasCurrentAnimationOfProperty(aProperty) ||
|
2014-06-26 23:57:13 +00:00
|
|
|
!collection->CanPerformOnCompositorThread(
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::CanAnimate_AllowPartial)) {
|
2014-06-20 03:39:25 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2014-06-20 03:39:26 +00:00
|
|
|
|
|
|
|
// This animation can be done on the compositor.
|
2014-06-26 23:57:13 +00:00
|
|
|
return collection;
|
2014-06-20 03:39:25 +00:00
|
|
|
}
|
|
|
|
|
2011-04-12 06:18:43 +00:00
|
|
|
nsRestyleHint
|
|
|
|
CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
return nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2013-11-28 06:46:39 +00:00
|
|
|
nsRestyleHint
|
|
|
|
CommonAnimationManager::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
return nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2011-04-12 06:18:43 +00:00
|
|
|
CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
|
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRestyleHint
|
2015-08-05 12:42:21 +00:00
|
|
|
CommonAnimationManager::HasAttributeDependentStyle(
|
|
|
|
AttributeRuleProcessorData* aData,
|
|
|
|
RestyleHintData& aRestyleHintDataResult)
|
2011-04-12 06:18:43 +00:00
|
|
|
{
|
|
|
|
return nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
/* virtual */ bool
|
2011-04-12 06:18:43 +00:00
|
|
|
CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
|
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-20 02:48:41 +00:00
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(ElementRuleProcessorData* aData)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(aData->mPresContext == mPresContext,
|
|
|
|
"pres context mismatch");
|
2014-11-20 02:48:41 +00:00
|
|
|
nsIStyleRule *rule =
|
|
|
|
GetAnimationRule(aData->mElement,
|
|
|
|
nsCSSPseudoElements::ePseudo_NotPseudoElement);
|
|
|
|
if (rule) {
|
|
|
|
aData->mRuleWalker->Forward(rule);
|
2015-07-27 06:43:44 +00:00
|
|
|
aData->mRuleWalker->CurrentNode()->SetIsAnimationRule();
|
2014-11-20 02:48:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(PseudoElementRuleProcessorData* aData)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(aData->mPresContext == mPresContext,
|
|
|
|
"pres context mismatch");
|
2014-11-20 02:48:41 +00:00
|
|
|
if (aData->mPseudoType != nsCSSPseudoElements::ePseudo_before &&
|
|
|
|
aData->mPseudoType != nsCSSPseudoElements::ePseudo_after) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Do we really want to be the only thing keeping a
|
|
|
|
// pseudo-element alive? I *think* the non-animation restyle should
|
|
|
|
// handle that, but should add a test.
|
|
|
|
nsIStyleRule *rule = GetAnimationRule(aData->mElement, aData->mPseudoType);
|
|
|
|
if (rule) {
|
|
|
|
aData->mRuleWalker->Forward(rule);
|
2015-07-27 06:43:44 +00:00
|
|
|
aData->mRuleWalker->CurrentNode()->SetIsAnimationRule();
|
2014-11-20 02:48:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(AnonBoxRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(XULTreeRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-12-09 05:01:52 +00:00
|
|
|
/* virtual */ size_t
|
2013-06-23 12:03:39 +00:00
|
|
|
CommonAnimationManager::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
2011-08-01 18:25:20 +00:00
|
|
|
{
|
2012-01-03 02:19:14 +00:00
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
|
|
// worthwhile:
|
2014-06-26 23:57:13 +00:00
|
|
|
// - mElementCollections
|
2012-01-03 02:19:14 +00:00
|
|
|
//
|
|
|
|
// The following members are not measured
|
|
|
|
// - mPresContext, because it's non-owning
|
|
|
|
|
2011-12-09 05:01:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */ size_t
|
2013-06-23 12:03:39 +00:00
|
|
|
CommonAnimationManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
2011-12-09 05:01:52 +00:00
|
|
|
{
|
2012-01-25 08:52:51 +00:00
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
2011-08-01 18:25:20 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 05:58:44 +00:00
|
|
|
void
|
|
|
|
CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker)
|
|
|
|
{
|
2014-11-11 23:42:57 +00:00
|
|
|
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
|
|
|
|
|
2014-08-07 05:58:44 +00:00
|
|
|
PRCList* next = PR_LIST_HEAD(&mElementCollections);
|
|
|
|
while (next != &mElementCollections) {
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection* collection = static_cast<AnimationCollection*>(next);
|
2014-08-07 05:58:44 +00:00
|
|
|
next = PR_NEXT_LINK(next);
|
|
|
|
|
2014-11-11 23:42:57 +00:00
|
|
|
collection->EnsureStyleRuleFor(now, EnsureStyleRule_IsNotThrottled);
|
|
|
|
|
2014-08-25 04:48:22 +00:00
|
|
|
dom::Element* elementToRestyle = collection->GetElementToRestyle();
|
|
|
|
if (elementToRestyle) {
|
|
|
|
nsRestyleHint rshint = collection->IsForTransitions()
|
|
|
|
? eRestyle_CSSTransitions : eRestyle_CSSAnimations;
|
|
|
|
aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0));
|
2014-08-07 05:58:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:45:57 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
CommonAnimationManager::NotifyCollectionUpdated(AnimationCollection&
|
2014-11-17 04:45:57 +00:00
|
|
|
aCollection)
|
|
|
|
{
|
2015-03-24 00:06:06 +00:00
|
|
|
MaybeStartObservingRefreshDriver();
|
2014-11-17 04:45:57 +00:00
|
|
|
mPresContext->ClearLastStyleUpdateForAllAnimations();
|
2014-11-17 04:45:59 +00:00
|
|
|
mPresContext->RestyleManager()->IncrementAnimationGeneration();
|
|
|
|
aCollection.UpdateAnimationGeneration(mPresContext);
|
2014-11-17 04:45:57 +00:00
|
|
|
aCollection.PostRestyleForAnimation(mPresContext);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
/* static */ bool
|
2011-04-12 06:18:43 +00:00
|
|
|
CommonAnimationManager::ExtractComputedValueForTransition(
|
|
|
|
nsCSSProperty aProperty,
|
|
|
|
nsStyleContext* aStyleContext,
|
2014-06-24 06:29:54 +00:00
|
|
|
StyleAnimationValue& aComputedValue)
|
2011-04-12 06:18:43 +00:00
|
|
|
{
|
2014-06-24 06:29:54 +00:00
|
|
|
bool result = StyleAnimationValue::ExtractComputedValue(aProperty,
|
|
|
|
aStyleContext,
|
|
|
|
aComputedValue);
|
2011-04-12 06:18:43 +00:00
|
|
|
if (aProperty == eCSSProperty_visibility) {
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(aComputedValue.GetUnit() ==
|
|
|
|
StyleAnimationValue::eUnit_Enumerated,
|
|
|
|
"unexpected unit");
|
2011-04-12 06:18:43 +00:00
|
|
|
aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
|
2014-06-24 06:29:54 +00:00
|
|
|
StyleAnimationValue::eUnit_Visibility);
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection*
|
2015-03-20 18:20:49 +00:00
|
|
|
CommonAnimationManager::GetAnimations(dom::Element *aElement,
|
|
|
|
nsCSSPseudoElements::Type aPseudoType,
|
|
|
|
bool aCreateIfNeeded)
|
2014-11-20 02:48:41 +00:00
|
|
|
{
|
|
|
|
if (!aCreateIfNeeded && PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
|
|
|
// Early return for the most common case.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *propName;
|
|
|
|
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
|
|
|
propName = GetAnimationsAtom();
|
|
|
|
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
|
|
|
|
propName = GetAnimationsBeforeAtom();
|
|
|
|
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) {
|
|
|
|
propName = GetAnimationsAfterAtom();
|
|
|
|
} else {
|
|
|
|
NS_ASSERTION(!aCreateIfNeeded,
|
|
|
|
"should never try to create transitions for pseudo "
|
|
|
|
"other than :before or :after");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection* collection =
|
|
|
|
static_cast<AnimationCollection*>(aElement->GetProperty(propName));
|
2014-11-20 02:48:41 +00:00
|
|
|
if (!collection && aCreateIfNeeded) {
|
|
|
|
// FIXME: Consider arena-allocating?
|
2015-04-21 01:22:10 +00:00
|
|
|
collection = new AnimationCollection(aElement, propName, this);
|
2014-11-20 02:48:41 +00:00
|
|
|
nsresult rv =
|
|
|
|
aElement->SetProperty(propName, collection,
|
2015-04-21 01:22:10 +00:00
|
|
|
&AnimationCollection::PropertyDtor, false);
|
2014-11-20 02:48:41 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("SetProperty failed");
|
2015-07-01 15:55:51 +00:00
|
|
|
// The collection must be destroyed via PropertyDtor, otherwise
|
|
|
|
// mCalledPropertyDtor assertion is triggered in destructor.
|
|
|
|
AnimationCollection::PropertyDtor(aElement, propName, collection, nullptr);
|
2014-11-20 02:48:41 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2015-07-01 15:55:51 +00:00
|
|
|
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
2014-11-20 02:48:41 +00:00
|
|
|
aElement->SetMayHaveAnimations();
|
|
|
|
}
|
|
|
|
|
|
|
|
AddElementCollection(collection);
|
|
|
|
}
|
|
|
|
|
|
|
|
return collection;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIStyleRule*
|
|
|
|
CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
|
|
|
|
nsCSSPseudoElements::Type aPseudoType)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(
|
2014-11-20 02:48:41 +00:00
|
|
|
aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
|
|
|
|
aPseudoType == nsCSSPseudoElements::ePseudo_before ||
|
|
|
|
aPseudoType == nsCSSPseudoElements::ePseudo_after,
|
|
|
|
"forbidden pseudo type");
|
|
|
|
|
|
|
|
if (!mPresContext->IsDynamic()) {
|
|
|
|
// For print or print preview, ignore animations.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection* collection =
|
2015-03-20 18:20:49 +00:00
|
|
|
GetAnimations(aElement, aPseudoType, false);
|
2014-11-20 02:48:41 +00:00
|
|
|
if (!collection) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RestyleManager* restyleManager = mPresContext->RestyleManager();
|
|
|
|
if (restyleManager->SkipAnimationRules()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-03-24 00:06:06 +00:00
|
|
|
collection->EnsureStyleRuleFor(
|
|
|
|
mPresContext->RefreshDriver()->MostRecentRefresh(),
|
|
|
|
EnsureStyleRule_IsNotThrottled);
|
2014-11-20 02:48:41 +00:00
|
|
|
|
|
|
|
return collection->mStyleRule;
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:46:00 +00:00
|
|
|
/* static */ const CommonAnimationManager::LayerAnimationRecord
|
|
|
|
CommonAnimationManager::sLayerAnimationInfo[] =
|
|
|
|
{ { eCSSProperty_transform,
|
|
|
|
nsDisplayItem::TYPE_TRANSFORM,
|
|
|
|
nsChangeHint_UpdateTransformLayer },
|
|
|
|
{ eCSSProperty_opacity,
|
|
|
|
nsDisplayItem::TYPE_OPACITY,
|
|
|
|
nsChangeHint_UpdateOpacityLayer } };
|
|
|
|
|
2015-03-31 22:05:54 +00:00
|
|
|
/* static */ const CommonAnimationManager::LayerAnimationRecord*
|
|
|
|
CommonAnimationManager::LayerAnimationRecordFor(nsCSSProperty aProperty)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
|
|
|
|
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
|
|
|
|
"unexpected property");
|
|
|
|
const auto& info = sLayerAnimationInfo;
|
|
|
|
for (size_t i = 0; i < ArrayLength(info); ++i) {
|
|
|
|
if (aProperty == info[i].mProperty) {
|
|
|
|
return &info[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-03-31 22:05:54 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
/* static */ void
|
|
|
|
CommonAnimationManager::Initialize()
|
|
|
|
{
|
2015-07-29 01:57:39 +00:00
|
|
|
const auto& info = CommonAnimationManager::sLayerAnimationInfo;
|
2015-03-31 22:05:54 +00:00
|
|
|
for (size_t i = 0; i < ArrayLength(info); i++) {
|
|
|
|
auto record = info[i];
|
|
|
|
MOZ_ASSERT(nsCSSProps::PropHasFlags(record.mProperty,
|
|
|
|
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
|
|
|
|
"CSS property with entry in sLayerAnimationInfo does not "
|
|
|
|
"have the CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR flag");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that every property with the flag for animating on the
|
|
|
|
// compositor has an entry in sLayerAnimationInfo.
|
|
|
|
for (nsCSSProperty prop = nsCSSProperty(0);
|
|
|
|
prop < eCSSProperty_COUNT;
|
|
|
|
prop = nsCSSProperty(prop + 1)) {
|
|
|
|
if (nsCSSProps::PropHasFlags(prop,
|
|
|
|
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
|
|
|
|
bool found = false;
|
|
|
|
for (size_t i = 0; i < ArrayLength(info); i++) {
|
|
|
|
auto record = info[i];
|
|
|
|
if (record.mProperty == prop) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(found,
|
|
|
|
"CSS property with the CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR "
|
|
|
|
"flag does not have an entry in sLayerAnimationInfo");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
|
2011-04-12 06:18:43 +00:00
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
|
|
|
|
{
|
|
|
|
nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent();
|
|
|
|
if (contextParent && contextParent->HasPseudoElementData()) {
|
|
|
|
// Don't apply transitions or animations to things inside of
|
|
|
|
// pseudo-elements.
|
|
|
|
// FIXME (Bug 522599): Add tests for this.
|
2015-07-27 06:43:44 +00:00
|
|
|
|
|
|
|
// Prevent structs from being cached on the rule node since we're inside
|
|
|
|
// a pseudo-element, as we could determine cacheability differently
|
|
|
|
// when walking the rule tree for a style context that is not inside
|
|
|
|
// a pseudo-element. Note that nsRuleNode::GetStyle##name_ and GetStyleData
|
|
|
|
// will never look at cached structs when we're animating things inside
|
|
|
|
// a pseduo-element, so that we don't incorrectly return a struct that
|
|
|
|
// is only appropriate for non-pseudo-elements.
|
|
|
|
aRuleData->mConditions.SetUncacheable();
|
2011-04-12 06:18:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
|
2011-04-12 06:18:43 +00:00
|
|
|
PropertyValuePair &cv = mPropertyValuePairs[i];
|
|
|
|
if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
|
|
|
|
nsCSSProps::kSIDTable[cv.mProperty]))
|
|
|
|
{
|
|
|
|
nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty);
|
|
|
|
if (prop->GetUnit() == eCSSUnit_Null) {
|
|
|
|
#ifdef DEBUG
|
2011-09-29 06:19:26 +00:00
|
|
|
bool ok =
|
2011-04-12 06:18:43 +00:00
|
|
|
#endif
|
2014-06-24 06:29:54 +00:00
|
|
|
StyleAnimationValue::UncomputeValue(cv.mProperty, cv.mValue, *prop);
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(ok, "could not store computed value");
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/* virtual */ void
|
2012-08-22 15:56:38 +00:00
|
|
|
AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const
|
2011-04-12 06:18:43 +00:00
|
|
|
{
|
2014-11-27 06:29:44 +00:00
|
|
|
nsAutoCString str;
|
2014-11-27 06:29:44 +00:00
|
|
|
for (int32_t index = aIndent; --index >= 0; ) {
|
2014-11-27 06:29:44 +00:00
|
|
|
str.AppendLiteral(" ");
|
2014-11-27 06:29:44 +00:00
|
|
|
}
|
2014-11-27 06:29:44 +00:00
|
|
|
str.AppendLiteral("[anim values] { ");
|
2012-11-20 19:55:14 +00:00
|
|
|
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
|
|
|
|
const PropertyValuePair &pair = mPropertyValuePairs[i];
|
2014-11-27 06:29:44 +00:00
|
|
|
str.Append(nsCSSProps::GetStringValue(pair.mProperty));
|
|
|
|
str.AppendLiteral(": ");
|
2012-11-20 19:55:14 +00:00
|
|
|
nsAutoString value;
|
2014-06-24 06:29:54 +00:00
|
|
|
StyleAnimationValue::UncomputeValue(pair.mProperty, pair.mValue, value);
|
2014-11-27 06:29:44 +00:00
|
|
|
AppendUTF16toUTF8(value, str);
|
|
|
|
str.AppendLiteral("; ");
|
2012-11-20 19:55:14 +00:00
|
|
|
}
|
2014-11-27 06:29:44 +00:00
|
|
|
str.AppendLiteral("}\n");
|
|
|
|
fprintf_stderr(out, "%s", str.get());
|
2011-04-12 06:18:43 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-07-31 17:28:21 +00:00
|
|
|
bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::CanAnimatePropertyOnCompositor(
|
2014-06-26 23:57:12 +00:00
|
|
|
const dom::Element *aElement,
|
2014-06-26 23:57:13 +00:00
|
|
|
nsCSSProperty aProperty,
|
|
|
|
CanAnimateFlags aFlags)
|
2012-07-31 17:28:21 +00:00
|
|
|
{
|
2012-08-06 20:33:23 +00:00
|
|
|
bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
|
2015-05-08 13:56:36 +00:00
|
|
|
if (!gfxPlatform::OffMainThreadCompositingEnabled()) {
|
|
|
|
if (shouldLog) {
|
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Compositor disabled");
|
|
|
|
LogAsyncAnimationFailure(message);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 05:32:10 +00:00
|
|
|
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
|
2012-08-22 01:48:47 +00:00
|
|
|
if (IsGeometricProperty(aProperty)) {
|
|
|
|
if (shouldLog) {
|
2012-08-26 01:27:28 +00:00
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Async animation of geometric property '");
|
2012-12-11 21:12:47 +00:00
|
|
|
message.Append(nsCSSProps::GetStringValue(aProperty));
|
|
|
|
message.AppendLiteral("' is disabled");
|
2012-08-26 01:27:28 +00:00
|
|
|
LogAsyncAnimationFailure(message, aElement);
|
2012-08-22 01:48:47 +00:00
|
|
|
}
|
|
|
|
return false;
|
2012-08-05 17:03:43 +00:00
|
|
|
}
|
2012-08-03 06:32:13 +00:00
|
|
|
if (aProperty == eCSSProperty_transform) {
|
Bug 1176969 - Disable OMT animation for any frame in a preserve-3d scene rather than only frames whose parent and child are in a preserve-3d scene. r=mattwoodrow
frame->Preserves3D() is whether the frame's parent has transform-style:
preserve-3d, which means that the frame is part of the same 3-D scene as
its parent. frame->Preserves3DChildren() is whether the frame itself
has transform-style: preserve-3d, which means that the frame is part of
the same 3-D scene as its children.
Neither of these are valid cases for doing off-main-thread (OMT)
animation because all of the layers in a preserve-3d scene are currently
siblings of each other, rather than preserving ancestor/descendant
relationships. This means that it's not valid to animate transform of
the parent on the compositor because the compositor animation won't
update any of its children that have layers. Likewise, it's not valid
to animate transform of the child on the compositor because the code
that sends transform information to the compositor doesn't handle the
accumulation of transforms needed to get the "right" transform for the
child (i.e., with the transforms of its ancestors up to the top of the
3-D scene merged in).
This means that we do OMT animation for slightly fewer cases with the
patch than we did without the patch. This means it's pretty low risk in
terms of correctness, although there's a chance it might regress
performance on one of the (somewhat limited) set of cases where the
optimization was valid. (Bug 779598 covers doing OMT animation for
preserve-3d cases, and depends on the work ongoing in bug 1097464.)
The animate-preserve3d-parent.html reftest doesn't fail without the
patch, since something seems to invalidate in the test; it was testing
the testcase that showed correct behavior when the mouse was moving, so
this isn't incredibly surprising (although that invalidation from mouse
movement is itself worth debugging). The animate-preserve3d-child.html
test does fail without the patch, though.
(With an initial transform of none instead of the 30deg transform, both
tests also show an invalidation bug without the patch.)
2015-06-30 18:29:55 +00:00
|
|
|
if (frame->Preserves3D() ||
|
2012-08-03 06:32:13 +00:00
|
|
|
frame->Preserves3DChildren()) {
|
2012-08-06 20:33:23 +00:00
|
|
|
if (shouldLog) {
|
2012-08-26 01:27:28 +00:00
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' transforms is not supported. See bug 779598");
|
|
|
|
LogAsyncAnimationFailure(message, aElement);
|
2012-08-03 06:32:13 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-07-22 15:58:42 +00:00
|
|
|
// Note that testing BackfaceIsHidden() is not a sufficient test for
|
|
|
|
// what we need for animating backface-visibility correctly if we
|
|
|
|
// remove the above test for Preserves3DChildren(); that would require
|
|
|
|
// looking at backface-visibility on descendants as well.
|
|
|
|
if (frame->StyleDisplay()->BackfaceIsHidden()) {
|
|
|
|
if (shouldLog) {
|
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Gecko bug: Async animation of 'backface-visibility: hidden' transforms is not supported. See bug 1186204.");
|
|
|
|
LogAsyncAnimationFailure(message, aElement);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-22 01:48:47 +00:00
|
|
|
if (frame->IsSVGTransformed()) {
|
2012-08-06 20:33:23 +00:00
|
|
|
if (shouldLog) {
|
2012-08-26 01:27:28 +00:00
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported. See bug 779599");
|
|
|
|
LogAsyncAnimationFailure(message, aElement);
|
2012-08-03 06:32:13 +00:00
|
|
|
}
|
2012-07-31 17:28:21 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-11 21:12:43 +00:00
|
|
|
if (aFlags & CanAnimate_HasGeometricProperty) {
|
2012-08-22 01:48:47 +00:00
|
|
|
if (shouldLog) {
|
2012-08-26 01:27:28 +00:00
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties");
|
|
|
|
LogAsyncAnimationFailure(message, aElement);
|
2012-08-22 01:48:47 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-03 06:32:13 +00:00
|
|
|
}
|
2013-05-23 07:09:26 +00:00
|
|
|
bool enabled = nsLayoutUtils::AreAsyncAnimationsEnabled();
|
|
|
|
if (!enabled && shouldLog) {
|
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Async animations are disabled");
|
|
|
|
LogAsyncAnimationFailure(message);
|
|
|
|
}
|
2013-06-18 08:03:20 +00:00
|
|
|
bool propertyAllowed = (aProperty == eCSSProperty_transform) ||
|
|
|
|
(aProperty == eCSSProperty_opacity) ||
|
|
|
|
(aFlags & CanAnimate_AllowPartial);
|
|
|
|
return enabled && propertyAllowed;
|
2012-07-31 17:28:21 +00:00
|
|
|
}
|
|
|
|
|
2013-10-22 10:30:45 +00:00
|
|
|
/* static */ bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::IsCompositorAnimationDisabledForFrame(
|
2014-06-26 23:57:12 +00:00
|
|
|
nsIFrame* aFrame)
|
2013-10-22 10:30:45 +00:00
|
|
|
{
|
|
|
|
void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
|
|
|
|
return bool(reinterpret_cast<intptr_t>(prop));
|
|
|
|
}
|
|
|
|
|
2014-06-20 03:39:25 +00:00
|
|
|
bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::CanPerformOnCompositorThread(
|
2014-06-20 03:39:25 +00:00
|
|
|
CanAnimateFlags aFlags) const
|
|
|
|
{
|
2015-07-01 15:55:51 +00:00
|
|
|
dom::Element* element = GetElementToRestyle();
|
|
|
|
if (!element) {
|
2014-06-20 03:39:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-07-01 15:55:51 +00:00
|
|
|
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
|
|
|
|
if (!frame) {
|
2014-06-20 03:39:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
const Animation* anim = mAnimations[animIdx];
|
|
|
|
if (!anim->IsPlaying()) {
|
2014-08-10 07:06:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-03-27 09:01:00 +00:00
|
|
|
|
2015-04-30 13:06:43 +00:00
|
|
|
const KeyframeEffectReadOnly* effect = anim->GetEffect();
|
2015-04-21 01:22:10 +00:00
|
|
|
MOZ_ASSERT(effect, "A playing animation should have an effect");
|
2015-03-27 09:01:00 +00:00
|
|
|
|
2015-04-14 23:48:21 +00:00
|
|
|
for (size_t propIdx = 0, propEnd = effect->Properties().Length();
|
2014-06-20 03:39:25 +00:00
|
|
|
propIdx != propEnd; ++propIdx) {
|
2015-04-14 23:48:21 +00:00
|
|
|
if (IsGeometricProperty(effect->Properties()[propIdx].mProperty)) {
|
2014-06-20 03:39:25 +00:00
|
|
|
aFlags = CanAnimateFlags(aFlags | CanAnimate_HasGeometricProperty);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool existsProperty = false;
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
const Animation* anim = mAnimations[animIdx];
|
|
|
|
if (!anim->IsPlaying()) {
|
2014-06-20 03:39:25 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-04-30 13:06:43 +00:00
|
|
|
const KeyframeEffectReadOnly* effect = anim->GetEffect();
|
2015-04-21 01:22:10 +00:00
|
|
|
MOZ_ASSERT(effect, "A playing animation should have an effect");
|
2015-03-27 09:01:00 +00:00
|
|
|
|
2015-04-14 23:48:21 +00:00
|
|
|
existsProperty = existsProperty || effect->Properties().Length() > 0;
|
2014-06-20 03:39:25 +00:00
|
|
|
|
2015-04-14 23:48:21 +00:00
|
|
|
for (size_t propIdx = 0, propEnd = effect->Properties().Length();
|
2014-06-20 03:39:25 +00:00
|
|
|
propIdx != propEnd; ++propIdx) {
|
2015-04-14 23:48:21 +00:00
|
|
|
const AnimationProperty& prop = effect->Properties()[propIdx];
|
2015-07-01 15:55:51 +00:00
|
|
|
if (!CanAnimatePropertyOnCompositor(element,
|
2014-06-20 03:39:25 +00:00
|
|
|
prop.mProperty,
|
|
|
|
aFlags) ||
|
|
|
|
IsCompositorAnimationDisabledForFrame(frame)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No properties to animate
|
|
|
|
if (!existsProperty) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-31 22:05:54 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::PostUpdateLayerAnimations()
|
2015-03-31 22:05:54 +00:00
|
|
|
{
|
|
|
|
nsCSSPropertySet propsHandled;
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
const auto& properties = mAnimations[animIdx]->GetEffect()->Properties();
|
2015-03-31 22:05:54 +00:00
|
|
|
for (size_t propIdx = properties.Length(); propIdx-- != 0; ) {
|
|
|
|
nsCSSProperty prop = properties[propIdx].mProperty;
|
|
|
|
if (nsCSSProps::PropHasFlags(prop,
|
|
|
|
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
|
|
|
|
!propsHandled.HasProperty(prop)) {
|
|
|
|
propsHandled.AddProperty(prop);
|
2015-07-29 01:57:39 +00:00
|
|
|
nsChangeHint changeHint = CommonAnimationManager::
|
2015-03-31 22:05:54 +00:00
|
|
|
LayerAnimationRecordFor(prop)->mChangeHint;
|
|
|
|
dom::Element* element = GetElementToRestyle();
|
|
|
|
if (element) {
|
|
|
|
mManager->mPresContext->RestyleManager()->
|
|
|
|
PostRestyleEvent(element, nsRestyleHint(0), changeHint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 03:39:25 +00:00
|
|
|
bool
|
Bug 1181392 part 5 - Remove use of IsFinishedTransition from AnimationCollection::HasAnimationOfProperty; r=dbaron
AnimationCollection::HasAnimationOfProperty uses IsFinishedTransition to filter
out transitions that should otherwise be ignored. This is used in the following
places:
1. nsLayoutUtils::HasAnimations
The is only used by nsIFrame::BuildDisplayListForStackingContext to see if
there are any opacity animations
For this case, simply returning *current* animations would be sufficient
(since finished but filling animations should have already filled in the
display opacity)
2. CommonAnimationManager::GetAnimationsForCompositor
This should really only return *current* animations--that is, animations that
are running or scheduled to run. Finished animations never run on the
compositor. Indeed, only *playing* animations run on the compositor but, as
we will see in some of the cases below, it is sometimes useful to know that
an animation *will* run on the compositor in the near future (e.g. so we can
pre-render content).
The places where GetAnimationsForCompositor is used are:
- When building layers to add animations to layers in nsDisplayList--in this
case we skip any animations that aren't playing so if
GetAnimationsForCompositor only returned current animations that would be
more than sufficient.
- In nsLayoutUtils::HasAnimationsForCompositor. This in turn is used:
- In ChooseScaleAndSetTransform to see if the transform is being animated
on the compositor. If so, it calls
nsLayoutUtils::ComputeSuitableScaleForAnimation (which also calls
GetAnimationsForCompositor) and passes the result to
GetMinAndMaxScaleForAnimationProperty which we have already adjusted in
part 4 of this patch series to only deal with *relevant* animations
Relevant animations include both current animations and in effect
animations but we don't run forwards-filling animations on the compositor
so GetAnimationsForCompositor should NOT return them. Current animations
should be enough. In fact, playing animations should be enough but we
might want to pre-render layers at a suitable size during their delay
phase so returning current animations is probably ok.
- In nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay to add a fuzz
factor to the overflow rect for frames undergoing a transform animation
on the compositor. In this case too current animations should be
sufficient.
- In nsDisplayOpacity::NeedsActiveLayer to say "yes" if we are animating
opacity on the compositor. Presumably in this case it would be good to
say "yes" if the animation is in the delay phase too (as it currently
does). After the animation is finished, we should drop the layer, i.e.
current animations should be sufficient.
- In nsDisplayTransform::ShouldPrerenderTransformedContent. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to pre-render
transformed content for animations that are current.
- In nsDisplayTransform::GetLayerState. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to return active here
for current animations.
- In nsIFrame::IsTransformed. Here we test the display style to see if
there is a transform and also check if transform is being animated on the
compositor. As a result, we really only need HasAnimationsForCompositor
to return true for animations that are playing--otherwise the display
style will tell us if we're transformed or not. Returning true for all
current compositor animations (which is a superset of playing), however,
should not cause problems (we already return true for even more than
that).
- In nsIFrame::HasOpacityInternal which is much the same as
nsIFrame::IsTransformed and hence current should be fine.
3. AnimationCollection::CanThrottleAnimation
Here, HasAnimationOfProperty is used when looking for animations that would
disqualify us from throttling the animation by having an out-of-date layer
generation or being a transform animation that affects scroll and so requires
that we do the occasional main thread sample to update scrollbars.
It would seem like current animations are enough here too. One interesting
case is where we *had* a compositor animation but it has finished or been
cancelled. In that case, the animation won't be current and we should not
throttle the animation since we need to take it off its layer.
It turns out checking for current animations is still ok in this case too.
The reasoning is as follows:
- If the animation is newly-finished, we'll pick that up in
Animation::CanThrottle and return false then.
- If the animation is newly-idle then there are two cases:
If the cancelled animation was the only compositor animation then
AnimationCollection::CanPerformOnCompositorThread will notice that there
are no playing compositor animations and return false and
AnimationCollection::CanThrottleAnimation will never be called.
If there are other compositor animations running, then
AnimationCollection::CanThrottleAnimation will still return false because
whatever cancelled the animation will update the animation generation and
we'll notice the mismatch between the layer animation generation and the
animation generation on the collection.
Based on the above analysis it appears that making
AnimationCollection::HasAnimationOfProperty return only current animations (and
simulatneously renaming it to HasCurrentAnimationOfProperty) is safe. Indeed, in
effect, we already do this for transitions but not for animations. This patch
generalizes this behavior to all animations.
This patch also updates test_animations_omta.html since it was incorrectly
testing that a finished opacity animation was still running on the compositor.
Finished animations should not run on the compositor and the changes in this
patch cause that to happen. The reason we don't just update this test to check
for RunningOn.MainThread is that for opacity animations, unlike transform
animations, we can't detect if an opacity on a layer was set by animation or
not. As a result, for opacity animations we typically test the opacity on
either the main thread or compositor in order to allow for the case where an
animation-set opacity is still lingering on the compositor.
2015-08-07 03:29:36 +00:00
|
|
|
AnimationCollection::HasCurrentAnimationOfProperty(nsCSSProperty
|
|
|
|
aProperty) const
|
2014-06-20 03:39:25 +00:00
|
|
|
{
|
Bug 1181392 part 5 - Remove use of IsFinishedTransition from AnimationCollection::HasAnimationOfProperty; r=dbaron
AnimationCollection::HasAnimationOfProperty uses IsFinishedTransition to filter
out transitions that should otherwise be ignored. This is used in the following
places:
1. nsLayoutUtils::HasAnimations
The is only used by nsIFrame::BuildDisplayListForStackingContext to see if
there are any opacity animations
For this case, simply returning *current* animations would be sufficient
(since finished but filling animations should have already filled in the
display opacity)
2. CommonAnimationManager::GetAnimationsForCompositor
This should really only return *current* animations--that is, animations that
are running or scheduled to run. Finished animations never run on the
compositor. Indeed, only *playing* animations run on the compositor but, as
we will see in some of the cases below, it is sometimes useful to know that
an animation *will* run on the compositor in the near future (e.g. so we can
pre-render content).
The places where GetAnimationsForCompositor is used are:
- When building layers to add animations to layers in nsDisplayList--in this
case we skip any animations that aren't playing so if
GetAnimationsForCompositor only returned current animations that would be
more than sufficient.
- In nsLayoutUtils::HasAnimationsForCompositor. This in turn is used:
- In ChooseScaleAndSetTransform to see if the transform is being animated
on the compositor. If so, it calls
nsLayoutUtils::ComputeSuitableScaleForAnimation (which also calls
GetAnimationsForCompositor) and passes the result to
GetMinAndMaxScaleForAnimationProperty which we have already adjusted in
part 4 of this patch series to only deal with *relevant* animations
Relevant animations include both current animations and in effect
animations but we don't run forwards-filling animations on the compositor
so GetAnimationsForCompositor should NOT return them. Current animations
should be enough. In fact, playing animations should be enough but we
might want to pre-render layers at a suitable size during their delay
phase so returning current animations is probably ok.
- In nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay to add a fuzz
factor to the overflow rect for frames undergoing a transform animation
on the compositor. In this case too current animations should be
sufficient.
- In nsDisplayOpacity::NeedsActiveLayer to say "yes" if we are animating
opacity on the compositor. Presumably in this case it would be good to
say "yes" if the animation is in the delay phase too (as it currently
does). After the animation is finished, we should drop the layer, i.e.
current animations should be sufficient.
- In nsDisplayTransform::ShouldPrerenderTransformedContent. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to pre-render
transformed content for animations that are current.
- In nsDisplayTransform::GetLayerState. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to return active here
for current animations.
- In nsIFrame::IsTransformed. Here we test the display style to see if
there is a transform and also check if transform is being animated on the
compositor. As a result, we really only need HasAnimationsForCompositor
to return true for animations that are playing--otherwise the display
style will tell us if we're transformed or not. Returning true for all
current compositor animations (which is a superset of playing), however,
should not cause problems (we already return true for even more than
that).
- In nsIFrame::HasOpacityInternal which is much the same as
nsIFrame::IsTransformed and hence current should be fine.
3. AnimationCollection::CanThrottleAnimation
Here, HasAnimationOfProperty is used when looking for animations that would
disqualify us from throttling the animation by having an out-of-date layer
generation or being a transform animation that affects scroll and so requires
that we do the occasional main thread sample to update scrollbars.
It would seem like current animations are enough here too. One interesting
case is where we *had* a compositor animation but it has finished or been
cancelled. In that case, the animation won't be current and we should not
throttle the animation since we need to take it off its layer.
It turns out checking for current animations is still ok in this case too.
The reasoning is as follows:
- If the animation is newly-finished, we'll pick that up in
Animation::CanThrottle and return false then.
- If the animation is newly-idle then there are two cases:
If the cancelled animation was the only compositor animation then
AnimationCollection::CanPerformOnCompositorThread will notice that there
are no playing compositor animations and return false and
AnimationCollection::CanThrottleAnimation will never be called.
If there are other compositor animations running, then
AnimationCollection::CanThrottleAnimation will still return false because
whatever cancelled the animation will update the animation generation and
we'll notice the mismatch between the layer animation generation and the
animation generation on the collection.
Based on the above analysis it appears that making
AnimationCollection::HasAnimationOfProperty return only current animations (and
simulatneously renaming it to HasCurrentAnimationOfProperty) is safe. Indeed, in
effect, we already do this for transitions but not for animations. This patch
generalizes this behavior to all animations.
This patch also updates test_animations_omta.html since it was incorrectly
testing that a finished opacity animation was still running on the compositor.
Finished animations should not run on the compositor and the changes in this
patch cause that to happen. The reason we don't just update this test to check
for RunningOn.MainThread is that for opacity animations, unlike transform
animations, we can't detect if an opacity on a layer was set by animation or
not. As a result, for opacity animations we typically test the opacity on
either the main thread or compositor in order to allow for the case where an
animation-set opacity is still lingering on the compositor.
2015-08-07 03:29:36 +00:00
|
|
|
for (Animation* animation : mAnimations) {
|
|
|
|
if (animation->HasCurrentEffect() &&
|
|
|
|
animation->GetEffect()->HasAnimationOfProperty(aProperty)) {
|
2014-06-20 03:39:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-29 01:57:40 +00:00
|
|
|
/*static*/ nsString
|
|
|
|
AnimationCollection::PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType)
|
|
|
|
{
|
|
|
|
switch (aPseudoType) {
|
|
|
|
case nsCSSPseudoElements::ePseudo_before:
|
|
|
|
return NS_LITERAL_STRING("::before");
|
|
|
|
case nsCSSPseudoElements::ePseudo_after:
|
|
|
|
return NS_LITERAL_STRING("::after");
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT(aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
|
|
|
|
"Unexpected pseudo type");
|
|
|
|
return EmptyString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-25 04:48:22 +00:00
|
|
|
mozilla::dom::Element*
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::GetElementToRestyle() const
|
2014-08-25 04:48:22 +00:00
|
|
|
{
|
|
|
|
if (IsForElement()) {
|
|
|
|
return mElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* primaryFrame = mElement->GetPrimaryFrame();
|
|
|
|
if (!primaryFrame) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
nsIFrame* pseudoFrame;
|
|
|
|
if (IsForBeforePseudo()) {
|
|
|
|
pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
|
|
|
|
} else if (IsForAfterPseudo()) {
|
|
|
|
pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
|
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(false, "unknown mElementProperty");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!pseudoFrame) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return pseudoFrame->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:45:57 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::NotifyAnimationUpdated()
|
2014-11-17 04:45:57 +00:00
|
|
|
{
|
|
|
|
// On the next flush, force us to update the style rule
|
|
|
|
mNeedsRefreshes = true;
|
|
|
|
mStyleRuleRefreshTime = TimeStamp();
|
|
|
|
|
|
|
|
mManager->NotifyCollectionUpdated(*this);
|
|
|
|
}
|
|
|
|
|
2012-08-26 01:27:28 +00:00
|
|
|
/* static */ void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::LogAsyncAnimationFailure(nsCString& aMessage,
|
2012-08-26 01:27:28 +00:00
|
|
|
const nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (aContent) {
|
|
|
|
aMessage.AppendLiteral(" [");
|
2015-03-03 11:09:00 +00:00
|
|
|
aMessage.Append(nsAtomCString(aContent->NodeInfo()->NameAtom()));
|
2012-08-26 01:27:28 +00:00
|
|
|
|
|
|
|
nsIAtom* id = aContent->GetID();
|
|
|
|
if (id) {
|
|
|
|
aMessage.AppendLiteral(" with id '");
|
|
|
|
aMessage.Append(nsAtomCString(aContent->GetID()));
|
2014-05-22 03:48:51 +00:00
|
|
|
aMessage.Append('\'');
|
2012-08-26 01:27:28 +00:00
|
|
|
}
|
2014-05-22 03:48:51 +00:00
|
|
|
aMessage.Append(']');
|
2012-08-26 01:27:28 +00:00
|
|
|
}
|
2014-05-22 03:48:51 +00:00
|
|
|
aMessage.Append('\n');
|
2014-08-26 21:14:51 +00:00
|
|
|
printf_stderr("%s", aMessage.get());
|
2012-08-26 01:27:28 +00:00
|
|
|
}
|
2012-07-31 17:28:21 +00:00
|
|
|
|
2014-06-24 06:29:53 +00:00
|
|
|
/*static*/ void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::PropertyDtor(void *aObject, nsIAtom *aPropertyName,
|
|
|
|
void *aPropertyValue, void *aData)
|
2014-06-24 06:29:53 +00:00
|
|
|
{
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection* collection =
|
|
|
|
static_cast<AnimationCollection*>(aPropertyValue);
|
2014-06-24 06:29:53 +00:00
|
|
|
#ifdef DEBUG
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(!collection->mCalledPropertyDtor, "can't call dtor twice");
|
2014-06-26 23:57:13 +00:00
|
|
|
collection->mCalledPropertyDtor = true;
|
2014-06-24 06:29:53 +00:00
|
|
|
#endif
|
2015-06-09 02:13:53 +00:00
|
|
|
{
|
|
|
|
nsAutoAnimationMutationBatch mb(collection->mElement);
|
|
|
|
|
|
|
|
for (size_t animIdx = collection->mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
collection->mAnimations[animIdx]->CancelFromStyle();
|
|
|
|
}
|
|
|
|
}
|
2014-06-26 23:57:13 +00:00
|
|
|
delete collection;
|
2014-06-24 06:29:53 +00:00
|
|
|
}
|
|
|
|
|
2014-08-10 07:06:48 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::Tick()
|
2014-08-10 07:06:48 +00:00
|
|
|
{
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = 0, animEnd = mAnimations.Length();
|
|
|
|
animIdx != animEnd; animIdx++) {
|
|
|
|
mAnimations[animIdx]->Tick();
|
2014-08-10 07:06:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 03:39:24 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
|
|
|
|
EnsureStyleRuleFlags aFlags)
|
2014-06-20 03:39:24 +00:00
|
|
|
{
|
2015-08-17 04:59:44 +00:00
|
|
|
mHasPendingAnimationRestyle = false;
|
|
|
|
|
2014-06-20 03:39:24 +00:00
|
|
|
if (!mNeedsRefreshes) {
|
|
|
|
mStyleRuleRefreshTime = aRefreshTime;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-31 22:05:55 +00:00
|
|
|
if (!mStyleRuleRefreshTime.IsNull() &&
|
|
|
|
mStyleRuleRefreshTime == aRefreshTime) {
|
|
|
|
// mStyleRule may be null and valid, if we have no style to apply.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-20 03:39:24 +00:00
|
|
|
// If we're performing animations on the compositor thread, then we can skip
|
|
|
|
// most of the work in this method. But even if we are throttled, then we
|
|
|
|
// have to do the work if an animation is ending in order to get correct end
|
2014-12-04 20:37:28 +00:00
|
|
|
// of animation behavior (the styles of the animation disappear, or the fill
|
|
|
|
// mode behavior). CanThrottle returns false for any finishing animations
|
2014-10-20 04:55:45 +00:00
|
|
|
// so we can force style recalculation in that case.
|
2014-06-20 03:39:25 +00:00
|
|
|
if (aFlags == EnsureStyleRule_IsThrottled) {
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
if (!mAnimations[animIdx]->CanThrottle()) {
|
2014-06-20 03:39:25 +00:00
|
|
|
aFlags = EnsureStyleRule_IsNotThrottled;
|
2014-06-20 03:39:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 03:39:25 +00:00
|
|
|
if (aFlags == EnsureStyleRule_IsThrottled) {
|
2014-06-20 03:39:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-31 22:05:55 +00:00
|
|
|
if (mManager->IsAnimationManager()) {
|
|
|
|
// Update cascade results before updating the style rule, since the
|
|
|
|
// cascade results can influence the style rule.
|
|
|
|
static_cast<nsAnimationManager*>(mManager)->MaybeUpdateCascadeResults(this);
|
|
|
|
}
|
2014-06-20 03:39:24 +00:00
|
|
|
|
2015-03-31 22:05:55 +00:00
|
|
|
mStyleRuleRefreshTime = aRefreshTime;
|
|
|
|
mStyleRule = nullptr;
|
|
|
|
// We'll set mNeedsRefreshes to true below in all cases where we need them.
|
|
|
|
mNeedsRefreshes = false;
|
2014-06-20 03:39:24 +00:00
|
|
|
|
2015-03-31 22:05:55 +00:00
|
|
|
// If multiple animations specify behavior for the same property the
|
|
|
|
// animation which occurs last in the value of animation-name wins.
|
|
|
|
// As a result, we iterate from last animation to first and, if a
|
|
|
|
// property has already been set, we don't leave it.
|
|
|
|
nsCSSPropertySet properties;
|
2014-06-20 03:39:24 +00:00
|
|
|
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
mAnimations[animIdx]->ComposeStyle(mStyleRule, properties, mNeedsRefreshes);
|
2015-03-31 22:05:55 +00:00
|
|
|
}
|
2015-03-31 22:05:55 +00:00
|
|
|
|
2015-03-24 00:06:06 +00:00
|
|
|
mManager->MaybeStartObservingRefreshDriver();
|
2014-11-17 04:45:56 +00:00
|
|
|
}
|
2014-06-20 03:39:24 +00:00
|
|
|
|
2012-12-11 21:12:43 +00:00
|
|
|
bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::CanThrottleTransformChanges(TimeStamp aTime)
|
2012-12-11 21:12:43 +00:00
|
|
|
{
|
2013-05-22 10:31:03 +00:00
|
|
|
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
|
2012-12-11 21:12:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we know that the animation cannot cause overflow,
|
|
|
|
// we can just disable flushes for this animation.
|
|
|
|
|
|
|
|
// If we don't show scrollbars, we don't care about overflow.
|
|
|
|
if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this animation can cause overflow, we can throttle some of the ticks.
|
2014-11-17 04:46:00 +00:00
|
|
|
if (!mStyleRuleRefreshTime.IsNull() &&
|
|
|
|
(aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
|
2012-12-11 21:12:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-01 15:55:51 +00:00
|
|
|
dom::Element* element = GetElementToRestyle();
|
|
|
|
if (!element) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:12:43 +00:00
|
|
|
// If the nearest scrollable ancestor has overflow:hidden,
|
|
|
|
// we don't care about overflow.
|
2013-06-25 05:32:10 +00:00
|
|
|
nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
|
2015-07-01 15:55:51 +00:00
|
|
|
nsLayoutUtils::GetStyleFrame(element));
|
2012-12-11 21:12:43 +00:00
|
|
|
if (!scrollable) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-23 20:20:07 +00:00
|
|
|
ScrollbarStyles ss = scrollable->GetScrollbarStyles();
|
2012-12-11 21:12:43 +00:00
|
|
|
if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
|
|
|
|
ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
|
|
|
|
scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::CanThrottleAnimation(TimeStamp aTime)
|
2012-12-11 21:12:43 +00:00
|
|
|
{
|
2015-07-01 15:55:51 +00:00
|
|
|
dom::Element* element = GetElementToRestyle();
|
|
|
|
if (!element) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
|
2012-12-11 21:12:43 +00:00
|
|
|
if (!frame) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-29 01:57:39 +00:00
|
|
|
const auto& info = CommonAnimationManager::sLayerAnimationInfo;
|
2014-11-17 04:46:00 +00:00
|
|
|
for (size_t i = 0; i < ArrayLength(info); i++) {
|
|
|
|
auto record = info[i];
|
Bug 1181392 part 5 - Remove use of IsFinishedTransition from AnimationCollection::HasAnimationOfProperty; r=dbaron
AnimationCollection::HasAnimationOfProperty uses IsFinishedTransition to filter
out transitions that should otherwise be ignored. This is used in the following
places:
1. nsLayoutUtils::HasAnimations
The is only used by nsIFrame::BuildDisplayListForStackingContext to see if
there are any opacity animations
For this case, simply returning *current* animations would be sufficient
(since finished but filling animations should have already filled in the
display opacity)
2. CommonAnimationManager::GetAnimationsForCompositor
This should really only return *current* animations--that is, animations that
are running or scheduled to run. Finished animations never run on the
compositor. Indeed, only *playing* animations run on the compositor but, as
we will see in some of the cases below, it is sometimes useful to know that
an animation *will* run on the compositor in the near future (e.g. so we can
pre-render content).
The places where GetAnimationsForCompositor is used are:
- When building layers to add animations to layers in nsDisplayList--in this
case we skip any animations that aren't playing so if
GetAnimationsForCompositor only returned current animations that would be
more than sufficient.
- In nsLayoutUtils::HasAnimationsForCompositor. This in turn is used:
- In ChooseScaleAndSetTransform to see if the transform is being animated
on the compositor. If so, it calls
nsLayoutUtils::ComputeSuitableScaleForAnimation (which also calls
GetAnimationsForCompositor) and passes the result to
GetMinAndMaxScaleForAnimationProperty which we have already adjusted in
part 4 of this patch series to only deal with *relevant* animations
Relevant animations include both current animations and in effect
animations but we don't run forwards-filling animations on the compositor
so GetAnimationsForCompositor should NOT return them. Current animations
should be enough. In fact, playing animations should be enough but we
might want to pre-render layers at a suitable size during their delay
phase so returning current animations is probably ok.
- In nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay to add a fuzz
factor to the overflow rect for frames undergoing a transform animation
on the compositor. In this case too current animations should be
sufficient.
- In nsDisplayOpacity::NeedsActiveLayer to say "yes" if we are animating
opacity on the compositor. Presumably in this case it would be good to
say "yes" if the animation is in the delay phase too (as it currently
does). After the animation is finished, we should drop the layer, i.e.
current animations should be sufficient.
- In nsDisplayTransform::ShouldPrerenderTransformedContent. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to pre-render
transformed content for animations that are current.
- In nsDisplayTransform::GetLayerState. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to return active here
for current animations.
- In nsIFrame::IsTransformed. Here we test the display style to see if
there is a transform and also check if transform is being animated on the
compositor. As a result, we really only need HasAnimationsForCompositor
to return true for animations that are playing--otherwise the display
style will tell us if we're transformed or not. Returning true for all
current compositor animations (which is a superset of playing), however,
should not cause problems (we already return true for even more than
that).
- In nsIFrame::HasOpacityInternal which is much the same as
nsIFrame::IsTransformed and hence current should be fine.
3. AnimationCollection::CanThrottleAnimation
Here, HasAnimationOfProperty is used when looking for animations that would
disqualify us from throttling the animation by having an out-of-date layer
generation or being a transform animation that affects scroll and so requires
that we do the occasional main thread sample to update scrollbars.
It would seem like current animations are enough here too. One interesting
case is where we *had* a compositor animation but it has finished or been
cancelled. In that case, the animation won't be current and we should not
throttle the animation since we need to take it off its layer.
It turns out checking for current animations is still ok in this case too.
The reasoning is as follows:
- If the animation is newly-finished, we'll pick that up in
Animation::CanThrottle and return false then.
- If the animation is newly-idle then there are two cases:
If the cancelled animation was the only compositor animation then
AnimationCollection::CanPerformOnCompositorThread will notice that there
are no playing compositor animations and return false and
AnimationCollection::CanThrottleAnimation will never be called.
If there are other compositor animations running, then
AnimationCollection::CanThrottleAnimation will still return false because
whatever cancelled the animation will update the animation generation and
we'll notice the mismatch between the layer animation generation and the
animation generation on the collection.
Based on the above analysis it appears that making
AnimationCollection::HasAnimationOfProperty return only current animations (and
simulatneously renaming it to HasCurrentAnimationOfProperty) is safe. Indeed, in
effect, we already do this for transitions but not for animations. This patch
generalizes this behavior to all animations.
This patch also updates test_animations_omta.html since it was incorrectly
testing that a finished opacity animation was still running on the compositor.
Finished animations should not run on the compositor and the changes in this
patch cause that to happen. The reason we don't just update this test to check
for RunningOn.MainThread is that for opacity animations, unlike transform
animations, we can't detect if an opacity on a layer was set by animation or
not. As a result, for opacity animations we typically test the opacity on
either the main thread or compositor in order to allow for the case where an
animation-set opacity is still lingering on the compositor.
2015-08-07 03:29:36 +00:00
|
|
|
// We only need to worry about *current* animations here.
|
|
|
|
// - If we have a newly-finished animation, Animation::CanThrottle will
|
|
|
|
// detect that and force an unthrottled sample.
|
|
|
|
// - If we have a newly-idle animation, then whatever caused the animation
|
|
|
|
// to be idle will update the animation generation so we'll return false
|
|
|
|
// from the layer generation check below for any other running compositor
|
|
|
|
// animations (and if no other compositor animations exist we won't get
|
|
|
|
// this far).
|
|
|
|
if (!HasCurrentAnimationOfProperty(record.mProperty)) {
|
2014-11-17 04:46:00 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:12:43 +00:00
|
|
|
Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
|
2014-11-17 04:46:00 +00:00
|
|
|
frame, record.mLayerType);
|
2012-12-11 21:12:43 +00:00
|
|
|
if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:46:00 +00:00
|
|
|
if (record.mProperty == eCSSProperty_transform &&
|
|
|
|
!CanThrottleTransformChanges(aTime)) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-12-11 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-17 04:46:00 +00:00
|
|
|
return true;
|
2012-12-11 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2015-08-17 04:59:44 +00:00
|
|
|
void
|
|
|
|
AnimationCollection::RequestRestyle(RestyleType aRestyleType)
|
|
|
|
{
|
|
|
|
nsPresContext* presContext = mManager->PresContext();
|
|
|
|
if (!presContext) {
|
|
|
|
// Pres context will be null after the manager is disconnected.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-17 04:59:44 +00:00
|
|
|
// SetNeedStyleFlush is cheap and required regardless of the restyle type
|
|
|
|
// so we do it unconditionally. Furthermore, if the posted animation restyle
|
|
|
|
// has been postponed due to the element being display:none (i.e.
|
|
|
|
// mHasPendingAnimationRestyle is set) then we should still mark the
|
|
|
|
// document as needing a style flush.
|
|
|
|
presContext->Document()->SetNeedStyleFlush();
|
|
|
|
|
|
|
|
// If we are already waiting on an animation restyle then there's nothing
|
|
|
|
// more to do.
|
|
|
|
if (mHasPendingAnimationRestyle) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upgrade throttled restyles if other factors prevent
|
|
|
|
// throttling (e.g. async animations are not enabled).
|
|
|
|
if (aRestyleType == RestyleType::Throttled) {
|
|
|
|
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
|
|
|
|
if (!CanPerformOnCompositorThread(CanAnimateFlags(0)) ||
|
|
|
|
!CanThrottleAnimation(now)) {
|
|
|
|
aRestyleType = RestyleType::Standard;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aRestyleType == RestyleType::Standard) {
|
|
|
|
mHasPendingAnimationRestyle = true;
|
|
|
|
PostRestyleForAnimation(presContext);
|
2015-08-17 04:59:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-26 23:57:12 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::UpdateAnimationGeneration(nsPresContext* aPresContext)
|
2012-12-11 21:12:43 +00:00
|
|
|
{
|
|
|
|
mAnimationGeneration =
|
2013-07-20 19:14:25 +00:00
|
|
|
aPresContext->RestyleManager()->GetAnimationGeneration();
|
2012-12-11 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2015-02-16 22:15:03 +00:00
|
|
|
void
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::UpdateCheckGeneration(
|
2015-02-16 22:15:03 +00:00
|
|
|
nsPresContext* aPresContext)
|
|
|
|
{
|
|
|
|
mCheckGeneration =
|
|
|
|
aPresContext->RestyleManager()->GetAnimationGeneration();
|
|
|
|
}
|
|
|
|
|
2014-06-16 18:43:04 +00:00
|
|
|
bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::HasCurrentAnimations() const
|
2014-06-16 18:43:04 +00:00
|
|
|
{
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
if (mAnimations[animIdx]->HasCurrentEffect()) {
|
2014-06-16 18:43:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-02 06:14:13 +00:00
|
|
|
bool
|
2015-04-21 01:22:10 +00:00
|
|
|
AnimationCollection::HasCurrentAnimationsForProperties(
|
2015-04-06 02:53:51 +00:00
|
|
|
const nsCSSProperty* aProperties,
|
|
|
|
size_t aPropertyCount) const
|
2014-10-02 06:14:13 +00:00
|
|
|
{
|
2015-04-21 01:22:10 +00:00
|
|
|
for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
|
|
|
|
const Animation& anim = *mAnimations[animIdx];
|
2015-04-30 13:06:43 +00:00
|
|
|
const KeyframeEffectReadOnly* effect = anim.GetEffect();
|
2015-04-14 23:48:21 +00:00
|
|
|
if (effect &&
|
2015-04-21 01:22:10 +00:00
|
|
|
effect->IsCurrent(anim) &&
|
2015-04-14 23:48:21 +00:00
|
|
|
effect->HasAnimationOfProperties(aProperties, aPropertyCount)) {
|
2014-10-02 06:14:13 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-29 01:57:39 +00:00
|
|
|
nsPresContext*
|
|
|
|
OwningElementRef::GetRenderedPresContext() const
|
|
|
|
{
|
|
|
|
if (!mElement) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument* doc = mElement->GetComposedDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIPresShell* shell = doc->GetShell();
|
|
|
|
if (!shell) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shell->GetPresContext();
|
|
|
|
}
|
|
|
|
|
2015-07-13 15:25:42 +00:00
|
|
|
} // namespace mozilla
|