2011-04-12 10:18:43 +04:00
|
|
|
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
2012-05-21 15:12:37 +04: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 10:18:43 +04:00
|
|
|
|
2013-10-23 00:55:14 +04:00
|
|
|
#include "AnimationCommon.h"
|
2013-10-22 16:14:41 +04:00
|
|
|
#include "nsTransitionManager.h"
|
|
|
|
#include "nsAnimationManager.h"
|
|
|
|
|
2014-06-20 07:39:25 +04:00
|
|
|
#include "ActiveLayerTracker.h"
|
2013-10-22 16:14:41 +04:00
|
|
|
#include "gfxPlatform.h"
|
2011-04-12 10:18:43 +04:00
|
|
|
#include "nsRuleData.h"
|
2014-06-20 07:39:24 +04:00
|
|
|
#include "nsCSSPropertySet.h"
|
2011-04-12 10:18:43 +04:00
|
|
|
#include "nsCSSValue.h"
|
2014-07-16 04:02:30 +04:00
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2011-04-12 10:18:43 +04:00
|
|
|
#include "nsStyleContext.h"
|
2012-07-31 21:28:21 +04:00
|
|
|
#include "nsIFrame.h"
|
2012-07-31 21:28:22 +04:00
|
|
|
#include "nsLayoutUtils.h"
|
2012-12-12 01:12:43 +04:00
|
|
|
#include "mozilla/LookAndFeel.h"
|
|
|
|
#include "Layers.h"
|
|
|
|
#include "FrameLayerBuilder.h"
|
|
|
|
#include "nsDisplayList.h"
|
2013-06-23 16:03:39 +04:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2015-04-15 02:48:21 +03:00
|
|
|
#include "mozilla/dom/KeyframeEffect.h"
|
2013-08-20 02:55:18 +04:00
|
|
|
#include "RestyleManager.h"
|
2014-11-20 05:48:41 +03:00
|
|
|
#include "nsRuleProcessorData.h"
|
2013-10-22 16:14:41 +04:00
|
|
|
#include "nsStyleSet.h"
|
|
|
|
#include "nsStyleChangeList.h"
|
|
|
|
|
2012-12-12 01:12:43 +04:00
|
|
|
|
2014-04-03 09:57:28 +04:00
|
|
|
using mozilla::layers::Layer;
|
2014-08-10 11:06:44 +04:00
|
|
|
using mozilla::dom::AnimationPlayer;
|
2015-04-15 02:48:21 +03:00
|
|
|
using mozilla::dom::KeyframeEffectReadonly;
|
2011-04-12 10:18:43 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2012-08-22 05:48:47 +04: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 03:57:12 +04:00
|
|
|
namespace css {
|
|
|
|
|
2011-04-12 10:18:43 +04:00
|
|
|
CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext)
|
|
|
|
: mPresContext(aPresContext)
|
2014-11-17 07:45:56 +03:00
|
|
|
, mIsObservingRefreshDriver(false)
|
2011-04-12 10:18:43 +04:00
|
|
|
{
|
2014-06-27 03:57:13 +04:00
|
|
|
PR_INIT_CLIST(&mElementCollections);
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
CommonAnimationManager::~CommonAnimationManager()
|
|
|
|
{
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(!mPresContext, "Disconnect should have been called");
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CommonAnimationManager::Disconnect()
|
|
|
|
{
|
|
|
|
// Content nodes might outlive the transition or animation manager.
|
2014-06-27 03:57:13 +04:00
|
|
|
RemoveAllElementCollections();
|
2011-04-12 10:18:43 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mPresContext = nullptr;
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
|
2014-11-17 07:45:56 +03:00
|
|
|
void
|
|
|
|
CommonAnimationManager::AddElementCollection(AnimationPlayerCollection*
|
|
|
|
aCollection)
|
|
|
|
{
|
|
|
|
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 10:18:43 +04:00
|
|
|
void
|
2014-06-27 03:57:13 +04:00
|
|
|
CommonAnimationManager::RemoveAllElementCollections()
|
2011-04-12 10:18:43 +04:00
|
|
|
{
|
2014-06-27 03:57:13 +04:00
|
|
|
while (!PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection* head =
|
|
|
|
static_cast<AnimationPlayerCollection*>(
|
2014-06-27 03:57:13 +04:00
|
|
|
PR_LIST_HEAD(&mElementCollections));
|
2011-04-12 10:18:43 +04:00
|
|
|
head->Destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 07:45:56 +03:00
|
|
|
void
|
2015-03-24 03:06:06 +03: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 07:45:56 +03:00
|
|
|
{
|
|
|
|
for (PRCList *l = PR_LIST_HEAD(&mElementCollections);
|
|
|
|
l != &mElementCollections;
|
|
|
|
l = PR_NEXT_LINK(l)) {
|
|
|
|
if (static_cast<AnimationPlayerCollection*>(l)->mNeedsRefreshes) {
|
2015-03-24 03:06:06 +03:00
|
|
|
return true;
|
2014-11-17 07:45:56 +03:00
|
|
|
}
|
|
|
|
}
|
2015-03-24 03:06:06 +03:00
|
|
|
return false;
|
2014-11-17 07:45:56 +03:00
|
|
|
}
|
|
|
|
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection*
|
2014-06-20 07:39:25 +04:00
|
|
|
CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
|
2015-04-07 04:13:48 +03:00
|
|
|
nsIAtom* aElementProperty,
|
|
|
|
nsCSSProperty aProperty)
|
2014-06-20 07:39:25 +04:00
|
|
|
{
|
|
|
|
if (!aContent->MayHaveAnimations())
|
|
|
|
return nullptr;
|
2015-04-01 06:23:24 +03:00
|
|
|
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection* collection =
|
|
|
|
static_cast<AnimationPlayerCollection*>(
|
2014-06-20 07:39:25 +04:00
|
|
|
aContent->GetProperty(aElementProperty));
|
2014-06-27 03:57:13 +04:00
|
|
|
if (!collection ||
|
|
|
|
!collection->HasAnimationOfProperty(aProperty) ||
|
|
|
|
!collection->CanPerformOnCompositorThread(
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::CanAnimate_AllowPartial)) {
|
2014-06-20 07:39:25 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2014-06-20 07:39:26 +04:00
|
|
|
|
|
|
|
// This animation can be done on the compositor.
|
2014-06-27 03:57:13 +04:00
|
|
|
return collection;
|
2014-06-20 07:39:25 +04:00
|
|
|
}
|
|
|
|
|
2011-04-12 10:18:43 +04:00
|
|
|
/*
|
|
|
|
* nsISupports implementation
|
|
|
|
*/
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(CommonAnimationManager, nsIStyleRuleProcessor)
|
2011-04-12 10:18:43 +04:00
|
|
|
|
|
|
|
nsRestyleHint
|
|
|
|
CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
return nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:46:39 +04:00
|
|
|
nsRestyleHint
|
|
|
|
CommonAnimationManager::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
return nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2011-04-12 10:18:43 +04:00
|
|
|
CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRestyleHint
|
|
|
|
CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
return nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
/* virtual */ bool
|
2011-04-12 10:18:43 +04:00
|
|
|
CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
|
2014-11-20 05:48:41 +03:00
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(ElementRuleProcessorData* aData)
|
|
|
|
{
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aData->mPresContext == mPresContext,
|
|
|
|
"pres context mismatch");
|
2014-11-20 05:48:41 +03:00
|
|
|
nsIStyleRule *rule =
|
|
|
|
GetAnimationRule(aData->mElement,
|
|
|
|
nsCSSPseudoElements::ePseudo_NotPseudoElement);
|
|
|
|
if (rule) {
|
|
|
|
aData->mRuleWalker->Forward(rule);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(PseudoElementRuleProcessorData* aData)
|
|
|
|
{
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aData->mPresContext == mPresContext,
|
|
|
|
"pres context mismatch");
|
2014-11-20 05:48:41 +03: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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(AnonBoxRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
/* virtual */ void
|
|
|
|
CommonAnimationManager::RulesMatching(XULTreeRuleProcessorData* aData)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-12-09 09:01:52 +04:00
|
|
|
/* virtual */ size_t
|
2013-06-23 16:03:39 +04:00
|
|
|
CommonAnimationManager::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
2011-08-01 22:25:20 +04:00
|
|
|
{
|
2012-01-03 06:19:14 +04:00
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
|
|
// worthwhile:
|
2014-06-27 03:57:13 +04:00
|
|
|
// - mElementCollections
|
2012-01-03 06:19:14 +04:00
|
|
|
//
|
|
|
|
// The following members are not measured
|
|
|
|
// - mPresContext, because it's non-owning
|
|
|
|
|
2011-12-09 09:01:52 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */ size_t
|
2013-06-23 16:03:39 +04:00
|
|
|
CommonAnimationManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
2011-12-09 09:01:52 +04:00
|
|
|
{
|
2012-01-25 12:52:51 +04:00
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
2011-08-01 22:25:20 +04:00
|
|
|
}
|
|
|
|
|
2014-08-07 09:58:44 +04:00
|
|
|
void
|
|
|
|
CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker)
|
|
|
|
{
|
2014-11-12 02:42:57 +03:00
|
|
|
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
|
|
|
|
|
2014-08-07 09:58:44 +04:00
|
|
|
PRCList* next = PR_LIST_HEAD(&mElementCollections);
|
|
|
|
while (next != &mElementCollections) {
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection* collection =
|
|
|
|
static_cast<AnimationPlayerCollection*>(next);
|
2014-08-07 09:58:44 +04:00
|
|
|
next = PR_NEXT_LINK(next);
|
|
|
|
|
2014-11-12 02:42:57 +03:00
|
|
|
collection->EnsureStyleRuleFor(now, EnsureStyleRule_IsNotThrottled);
|
|
|
|
|
2014-08-25 08:48:22 +04: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 09:58:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 07:45:57 +03:00
|
|
|
void
|
|
|
|
CommonAnimationManager::NotifyCollectionUpdated(AnimationPlayerCollection&
|
|
|
|
aCollection)
|
|
|
|
{
|
2015-03-24 03:06:06 +03:00
|
|
|
MaybeStartObservingRefreshDriver();
|
2014-11-17 07:45:57 +03:00
|
|
|
mPresContext->ClearLastStyleUpdateForAllAnimations();
|
2014-11-17 07:45:59 +03:00
|
|
|
mPresContext->RestyleManager()->IncrementAnimationGeneration();
|
|
|
|
aCollection.UpdateAnimationGeneration(mPresContext);
|
2014-11-17 07:45:57 +03:00
|
|
|
aCollection.PostRestyleForAnimation(mPresContext);
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
/* static */ bool
|
2011-04-12 10:18:43 +04:00
|
|
|
CommonAnimationManager::ExtractComputedValueForTransition(
|
|
|
|
nsCSSProperty aProperty,
|
|
|
|
nsStyleContext* aStyleContext,
|
2014-06-24 10:29:54 +04:00
|
|
|
StyleAnimationValue& aComputedValue)
|
2011-04-12 10:18:43 +04:00
|
|
|
{
|
2014-06-24 10:29:54 +04:00
|
|
|
bool result = StyleAnimationValue::ExtractComputedValue(aProperty,
|
|
|
|
aStyleContext,
|
|
|
|
aComputedValue);
|
2011-04-12 10:18:43 +04:00
|
|
|
if (aProperty == eCSSProperty_visibility) {
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aComputedValue.GetUnit() ==
|
|
|
|
StyleAnimationValue::eUnit_Enumerated,
|
|
|
|
"unexpected unit");
|
2011-04-12 10:18:43 +04:00
|
|
|
aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
|
2014-06-24 10:29:54 +04:00
|
|
|
StyleAnimationValue::eUnit_Visibility);
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-11-20 05:48:41 +03:00
|
|
|
AnimationPlayerCollection*
|
2015-03-20 21:20:49 +03:00
|
|
|
CommonAnimationManager::GetAnimations(dom::Element *aElement,
|
|
|
|
nsCSSPseudoElements::Type aPseudoType,
|
|
|
|
bool aCreateIfNeeded)
|
2014-11-20 05:48:41 +03: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;
|
|
|
|
}
|
|
|
|
AnimationPlayerCollection* collection =
|
|
|
|
static_cast<AnimationPlayerCollection*>(aElement->GetProperty(propName));
|
|
|
|
if (!collection && aCreateIfNeeded) {
|
|
|
|
// FIXME: Consider arena-allocating?
|
|
|
|
collection =
|
|
|
|
new AnimationPlayerCollection(aElement, propName, this);
|
|
|
|
nsresult rv =
|
|
|
|
aElement->SetProperty(propName, collection,
|
|
|
|
&AnimationPlayerCollection::PropertyDtor, false);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("SetProperty failed");
|
|
|
|
delete collection;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (propName == nsGkAtoms::animationsProperty ||
|
|
|
|
propName == nsGkAtoms::transitionsProperty) {
|
|
|
|
aElement->SetMayHaveAnimations();
|
|
|
|
}
|
|
|
|
|
|
|
|
AddElementCollection(collection);
|
|
|
|
}
|
|
|
|
|
|
|
|
return collection;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIStyleRule*
|
|
|
|
CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
|
|
|
|
nsCSSPseudoElements::Type aPseudoType)
|
|
|
|
{
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(
|
2014-11-20 05:48:41 +03: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationPlayerCollection* collection =
|
2015-03-20 21:20:49 +03:00
|
|
|
GetAnimations(aElement, aPseudoType, false);
|
2014-11-20 05:48:41 +03:00
|
|
|
if (!collection) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RestyleManager* restyleManager = mPresContext->RestyleManager();
|
|
|
|
if (restyleManager->SkipAnimationRules()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-03-24 03:06:06 +03:00
|
|
|
collection->EnsureStyleRuleFor(
|
|
|
|
mPresContext->RefreshDriver()->MostRecentRefresh(),
|
|
|
|
EnsureStyleRule_IsNotThrottled);
|
2014-11-20 05:48:41 +03:00
|
|
|
|
|
|
|
return collection->mStyleRule;
|
|
|
|
}
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
/* static */ const CommonAnimationManager::LayerAnimationRecord
|
|
|
|
CommonAnimationManager::sLayerAnimationInfo[] =
|
|
|
|
{ { eCSSProperty_transform,
|
|
|
|
nsDisplayItem::TYPE_TRANSFORM,
|
|
|
|
nsChangeHint_UpdateTransformLayer },
|
|
|
|
{ eCSSProperty_opacity,
|
|
|
|
nsDisplayItem::TYPE_OPACITY,
|
|
|
|
nsChangeHint_UpdateOpacityLayer } };
|
|
|
|
|
2015-04-01 01:05:54 +03: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-04-01 01:05:54 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
/* static */ void
|
|
|
|
CommonAnimationManager::Initialize()
|
|
|
|
{
|
|
|
|
const auto& info = css::CommonAnimationManager::sLayerAnimationInfo;
|
|
|
|
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 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
|
2011-04-12 10:18:43 +04: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.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
|
2011-04-12 10:18:43 +04: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 10:19:26 +04:00
|
|
|
bool ok =
|
2011-04-12 10:18:43 +04:00
|
|
|
#endif
|
2014-06-24 10:29:54 +04:00
|
|
|
StyleAnimationValue::UncomputeValue(cv.mProperty, cv.mValue, *prop);
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(ok, "could not store computed value");
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/* virtual */ void
|
2012-08-22 19:56:38 +04:00
|
|
|
AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const
|
2011-04-12 10:18:43 +04:00
|
|
|
{
|
2014-11-27 09:29:44 +03:00
|
|
|
nsAutoCString str;
|
2014-11-27 09:29:44 +03:00
|
|
|
for (int32_t index = aIndent; --index >= 0; ) {
|
2014-11-27 09:29:44 +03:00
|
|
|
str.AppendLiteral(" ");
|
2014-11-27 09:29:44 +03:00
|
|
|
}
|
2014-11-27 09:29:44 +03:00
|
|
|
str.AppendLiteral("[anim values] { ");
|
2012-11-20 23:55:14 +04:00
|
|
|
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
|
|
|
|
const PropertyValuePair &pair = mPropertyValuePairs[i];
|
2014-11-27 09:29:44 +03:00
|
|
|
str.Append(nsCSSProps::GetStringValue(pair.mProperty));
|
|
|
|
str.AppendLiteral(": ");
|
2012-11-20 23:55:14 +04:00
|
|
|
nsAutoString value;
|
2014-06-24 10:29:54 +04:00
|
|
|
StyleAnimationValue::UncomputeValue(pair.mProperty, pair.mValue, value);
|
2014-11-27 09:29:44 +03:00
|
|
|
AppendUTF16toUTF8(value, str);
|
|
|
|
str.AppendLiteral("; ");
|
2012-11-20 23:55:14 +04:00
|
|
|
}
|
2014-11-27 09:29:44 +03:00
|
|
|
str.AppendLiteral("}\n");
|
|
|
|
fprintf_stderr(out, "%s", str.get());
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-04-03 09:57:28 +04:00
|
|
|
} /* end sub-namespace css */
|
|
|
|
|
2012-07-31 21:28:21 +04:00
|
|
|
bool
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::CanAnimatePropertyOnCompositor(
|
2014-06-27 03:57:12 +04:00
|
|
|
const dom::Element *aElement,
|
2014-06-27 03:57:13 +04:00
|
|
|
nsCSSProperty aProperty,
|
|
|
|
CanAnimateFlags aFlags)
|
2012-07-31 21:28:21 +04:00
|
|
|
{
|
2012-08-07 00:33:23 +04:00
|
|
|
bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
|
2014-03-05 08:13:22 +04:00
|
|
|
if (!gfxPlatform::OffMainThreadCompositingEnabled()) {
|
|
|
|
if (shouldLog) {
|
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Compositor disabled");
|
|
|
|
LogAsyncAnimationFailure(message);
|
|
|
|
}
|
2012-08-26 05:27:28 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 09:32:10 +04:00
|
|
|
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
|
2012-08-22 05:48:47 +04:00
|
|
|
if (IsGeometricProperty(aProperty)) {
|
|
|
|
if (shouldLog) {
|
2012-08-26 05:27:28 +04:00
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Async animation of geometric property '");
|
2012-12-12 01:12:47 +04:00
|
|
|
message.Append(nsCSSProps::GetStringValue(aProperty));
|
|
|
|
message.AppendLiteral("' is disabled");
|
2012-08-26 05:27:28 +04:00
|
|
|
LogAsyncAnimationFailure(message, aElement);
|
2012-08-22 05:48:47 +04:00
|
|
|
}
|
|
|
|
return false;
|
2012-08-05 21:03:43 +04:00
|
|
|
}
|
2012-08-03 10:32:13 +04:00
|
|
|
if (aProperty == eCSSProperty_transform) {
|
2012-08-22 05:48:47 +04:00
|
|
|
if (frame->Preserves3D() &&
|
2012-08-03 10:32:13 +04:00
|
|
|
frame->Preserves3DChildren()) {
|
2012-08-07 00:33:23 +04:00
|
|
|
if (shouldLog) {
|
2012-08-26 05:27:28 +04: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 10:32:13 +04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-22 05:48:47 +04:00
|
|
|
if (frame->IsSVGTransformed()) {
|
2012-08-07 00:33:23 +04:00
|
|
|
if (shouldLog) {
|
2012-08-26 05:27:28 +04: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 10:32:13 +04:00
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-12 01:12:43 +04:00
|
|
|
if (aFlags & CanAnimate_HasGeometricProperty) {
|
2012-08-22 05:48:47 +04:00
|
|
|
if (shouldLog) {
|
2012-08-26 05:27:28 +04: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 05:48:47 +04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-03 10:32:13 +04:00
|
|
|
}
|
2013-05-23 11:09:26 +04:00
|
|
|
bool enabled = nsLayoutUtils::AreAsyncAnimationsEnabled();
|
|
|
|
if (!enabled && shouldLog) {
|
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Performance warning: Async animations are disabled");
|
|
|
|
LogAsyncAnimationFailure(message);
|
|
|
|
}
|
2013-06-18 12:03:20 +04:00
|
|
|
bool propertyAllowed = (aProperty == eCSSProperty_transform) ||
|
|
|
|
(aProperty == eCSSProperty_opacity) ||
|
|
|
|
(aFlags & CanAnimate_AllowPartial);
|
|
|
|
return enabled && propertyAllowed;
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
|
|
|
|
2013-10-22 14:30:45 +04:00
|
|
|
/* static */ bool
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::IsCompositorAnimationDisabledForFrame(
|
2014-06-27 03:57:12 +04:00
|
|
|
nsIFrame* aFrame)
|
2013-10-22 14:30:45 +04:00
|
|
|
{
|
|
|
|
void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
|
|
|
|
return bool(reinterpret_cast<intptr_t>(prop));
|
|
|
|
}
|
|
|
|
|
2014-06-20 07:39:25 +04:00
|
|
|
bool
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::CanPerformOnCompositorThread(
|
2014-06-20 07:39:25 +04:00
|
|
|
CanAnimateFlags aFlags) const
|
|
|
|
{
|
|
|
|
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
|
|
|
|
if (!frame) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mElementProperty != nsGkAtoms::transitionsProperty &&
|
|
|
|
mElementProperty != nsGkAtoms::animationsProperty) {
|
|
|
|
if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
|
|
|
|
nsCString message;
|
|
|
|
message.AppendLiteral("Gecko bug: Async animation of pseudoelements"
|
|
|
|
" not supported. See bug 771367 (");
|
|
|
|
message.Append(nsAtomCString(mElementProperty));
|
|
|
|
message.Append(")");
|
|
|
|
LogAsyncAnimationFailure(message, mElement);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-10 11:06:48 +04:00
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
|
|
|
const AnimationPlayer* player = mPlayers[playerIdx];
|
2015-03-27 12:01:00 +03:00
|
|
|
if (!player->IsPlaying()) {
|
2014-08-10 11:06:49 +04:00
|
|
|
continue;
|
|
|
|
}
|
2015-03-27 12:01:00 +03:00
|
|
|
|
2015-04-15 02:48:21 +03:00
|
|
|
const KeyframeEffectReadonly* effect = player->GetSource();
|
|
|
|
MOZ_ASSERT(effect, "A playing player should have an effect");
|
2015-03-27 12:01:00 +03:00
|
|
|
|
2015-04-15 02:48:21 +03:00
|
|
|
for (size_t propIdx = 0, propEnd = effect->Properties().Length();
|
2014-06-20 07:39:25 +04:00
|
|
|
propIdx != propEnd; ++propIdx) {
|
2015-04-15 02:48:21 +03:00
|
|
|
if (IsGeometricProperty(effect->Properties()[propIdx].mProperty)) {
|
2014-06-20 07:39:25 +04:00
|
|
|
aFlags = CanAnimateFlags(aFlags | CanAnimate_HasGeometricProperty);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool existsProperty = false;
|
2014-08-10 11:06:48 +04:00
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
|
|
|
const AnimationPlayer* player = mPlayers[playerIdx];
|
2015-03-27 12:01:00 +03:00
|
|
|
if (!player->IsPlaying()) {
|
2014-06-20 07:39:25 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-04-15 02:48:21 +03:00
|
|
|
const KeyframeEffectReadonly* effect = player->GetSource();
|
|
|
|
MOZ_ASSERT(effect, "A playing player should have an effect");
|
2015-03-27 12:01:00 +03:00
|
|
|
|
2015-04-15 02:48:21 +03:00
|
|
|
existsProperty = existsProperty || effect->Properties().Length() > 0;
|
2014-06-20 07:39:25 +04:00
|
|
|
|
2015-04-15 02:48:21 +03:00
|
|
|
for (size_t propIdx = 0, propEnd = effect->Properties().Length();
|
2014-06-20 07:39:25 +04:00
|
|
|
propIdx != propEnd; ++propIdx) {
|
2015-04-15 02:48:21 +03:00
|
|
|
const AnimationProperty& prop = effect->Properties()[propIdx];
|
2014-06-20 07:39:25 +04:00
|
|
|
if (!CanAnimatePropertyOnCompositor(mElement,
|
|
|
|
prop.mProperty,
|
|
|
|
aFlags) ||
|
|
|
|
IsCompositorAnimationDisabledForFrame(frame)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No properties to animate
|
|
|
|
if (!existsProperty) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-01 01:05:54 +03:00
|
|
|
void
|
|
|
|
AnimationPlayerCollection::PostUpdateLayerAnimations()
|
|
|
|
{
|
|
|
|
nsCSSPropertySet propsHandled;
|
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
|
|
|
const auto& properties = mPlayers[playerIdx]->GetSource()->Properties();
|
|
|
|
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);
|
|
|
|
nsChangeHint changeHint = css::CommonAnimationManager::
|
|
|
|
LayerAnimationRecordFor(prop)->mChangeHint;
|
|
|
|
dom::Element* element = GetElementToRestyle();
|
|
|
|
if (element) {
|
|
|
|
mManager->mPresContext->RestyleManager()->
|
|
|
|
PostRestyleEvent(element, nsRestyleHint(0), changeHint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 07:39:25 +04:00
|
|
|
bool
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::HasAnimationOfProperty(
|
2014-06-20 07:39:25 +04:00
|
|
|
nsCSSProperty aProperty) const
|
|
|
|
{
|
2014-08-10 11:06:48 +04:00
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
2015-04-15 02:48:21 +03:00
|
|
|
const KeyframeEffectReadonly* effect = mPlayers[playerIdx]->GetSource();
|
|
|
|
if (effect && effect->HasAnimationOfProperty(aProperty) &&
|
|
|
|
!effect->IsFinishedTransition()) {
|
2014-06-20 07:39:25 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-25 08:48:22 +04:00
|
|
|
mozilla::dom::Element*
|
|
|
|
AnimationPlayerCollection::GetElementToRestyle() const
|
|
|
|
{
|
|
|
|
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 07:45:57 +03:00
|
|
|
void
|
|
|
|
AnimationPlayerCollection::NotifyPlayerUpdated()
|
|
|
|
{
|
|
|
|
// On the next flush, force us to update the style rule
|
|
|
|
mNeedsRefreshes = true;
|
|
|
|
mStyleRuleRefreshTime = TimeStamp();
|
|
|
|
|
|
|
|
mManager->NotifyCollectionUpdated(*this);
|
|
|
|
}
|
|
|
|
|
2012-08-26 05:27:28 +04:00
|
|
|
/* static */ void
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::LogAsyncAnimationFailure(nsCString& aMessage,
|
2012-08-26 05:27:28 +04:00
|
|
|
const nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (aContent) {
|
|
|
|
aMessage.AppendLiteral(" [");
|
2015-03-03 14:09:00 +03:00
|
|
|
aMessage.Append(nsAtomCString(aContent->NodeInfo()->NameAtom()));
|
2012-08-26 05:27:28 +04:00
|
|
|
|
|
|
|
nsIAtom* id = aContent->GetID();
|
|
|
|
if (id) {
|
|
|
|
aMessage.AppendLiteral(" with id '");
|
|
|
|
aMessage.Append(nsAtomCString(aContent->GetID()));
|
2014-05-22 07:48:51 +04:00
|
|
|
aMessage.Append('\'');
|
2012-08-26 05:27:28 +04:00
|
|
|
}
|
2014-05-22 07:48:51 +04:00
|
|
|
aMessage.Append(']');
|
2012-08-26 05:27:28 +04:00
|
|
|
}
|
2014-05-22 07:48:51 +04:00
|
|
|
aMessage.Append('\n');
|
2014-08-27 01:14:51 +04:00
|
|
|
printf_stderr("%s", aMessage.get());
|
2012-08-26 05:27:28 +04:00
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2014-06-24 10:29:53 +04:00
|
|
|
/*static*/ void
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::PropertyDtor(void *aObject, nsIAtom *aPropertyName,
|
2014-06-24 10:29:53 +04:00
|
|
|
void *aPropertyValue, void *aData)
|
|
|
|
{
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection* collection =
|
|
|
|
static_cast<AnimationPlayerCollection*>(aPropertyValue);
|
2014-06-24 10:29:53 +04:00
|
|
|
#ifdef DEBUG
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(!collection->mCalledPropertyDtor, "can't call dtor twice");
|
2014-06-27 03:57:13 +04:00
|
|
|
collection->mCalledPropertyDtor = true;
|
2014-06-24 10:29:53 +04:00
|
|
|
#endif
|
2014-06-27 03:57:13 +04:00
|
|
|
delete collection;
|
2014-06-24 10:29:53 +04:00
|
|
|
}
|
|
|
|
|
2014-08-10 11:06:48 +04:00
|
|
|
void
|
|
|
|
AnimationPlayerCollection::Tick()
|
|
|
|
{
|
2014-08-10 11:06:48 +04:00
|
|
|
for (size_t playerIdx = 0, playerEnd = mPlayers.Length();
|
|
|
|
playerIdx != playerEnd; playerIdx++) {
|
|
|
|
mPlayers[playerIdx]->Tick();
|
2014-08-10 11:06:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 07:39:24 +04:00
|
|
|
void
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
|
|
|
|
EnsureStyleRuleFlags aFlags)
|
2014-06-20 07:39:24 +04:00
|
|
|
{
|
|
|
|
if (!mNeedsRefreshes) {
|
|
|
|
mStyleRuleRefreshTime = aRefreshTime;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-01 01:05:55 +03:00
|
|
|
if (!mStyleRuleRefreshTime.IsNull() &&
|
|
|
|
mStyleRuleRefreshTime == aRefreshTime) {
|
|
|
|
// mStyleRule may be null and valid, if we have no style to apply.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-20 07:39:24 +04: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 23:37:28 +03: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 08:55:45 +04:00
|
|
|
// so we can force style recalculation in that case.
|
2014-06-20 07:39:25 +04:00
|
|
|
if (aFlags == EnsureStyleRule_IsThrottled) {
|
2014-08-10 11:06:48 +04:00
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
2014-10-20 08:55:45 +04:00
|
|
|
if (!mPlayers[playerIdx]->CanThrottle()) {
|
2014-06-20 07:39:25 +04:00
|
|
|
aFlags = EnsureStyleRule_IsNotThrottled;
|
2014-06-20 07:39:24 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 07:39:25 +04:00
|
|
|
if (aFlags == EnsureStyleRule_IsThrottled) {
|
2014-06-20 07:39:24 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-01 01:05:55 +03: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 07:39:24 +04:00
|
|
|
|
2015-04-01 01:05:55 +03:00
|
|
|
mStyleRuleRefreshTime = aRefreshTime;
|
|
|
|
mStyleRule = nullptr;
|
|
|
|
// We'll set mNeedsRefreshes to true below in all cases where we need them.
|
|
|
|
mNeedsRefreshes = false;
|
2014-06-20 07:39:24 +04:00
|
|
|
|
2015-04-01 01:05:55 +03: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 07:39:24 +04:00
|
|
|
|
2015-04-01 01:05:55 +03:00
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
|
|
|
mPlayers[playerIdx]->ComposeStyle(mStyleRule, properties, mNeedsRefreshes);
|
2015-04-01 01:05:55 +03:00
|
|
|
}
|
2015-04-01 01:05:55 +03:00
|
|
|
|
2015-03-24 03:06:06 +03:00
|
|
|
mManager->MaybeStartObservingRefreshDriver();
|
2014-11-17 07:45:56 +03:00
|
|
|
}
|
2014-06-20 07:39:24 +04:00
|
|
|
|
2012-12-12 01:12:43 +04:00
|
|
|
bool
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::CanThrottleTransformChanges(TimeStamp aTime)
|
2012-12-12 01:12:43 +04:00
|
|
|
{
|
2013-05-22 14:31:03 +04:00
|
|
|
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
|
2012-12-12 01:12:43 +04: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 07:46:00 +03:00
|
|
|
if (!mStyleRuleRefreshTime.IsNull() &&
|
|
|
|
(aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
|
2012-12-12 01:12:43 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the nearest scrollable ancestor has overflow:hidden,
|
|
|
|
// we don't care about overflow.
|
2013-06-25 09:32:10 +04:00
|
|
|
nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
|
|
|
|
nsLayoutUtils::GetStyleFrame(mElement));
|
2012-12-12 01:12:43 +04:00
|
|
|
if (!scrollable) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-24 00:20:07 +04:00
|
|
|
ScrollbarStyles ss = scrollable->GetScrollbarStyles();
|
2012-12-12 01:12:43 +04:00
|
|
|
if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
|
|
|
|
ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
|
|
|
|
scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::CanThrottleAnimation(TimeStamp aTime)
|
2012-12-12 01:12:43 +04:00
|
|
|
{
|
2013-06-25 09:32:10 +04:00
|
|
|
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
|
2012-12-12 01:12:43 +04:00
|
|
|
if (!frame) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
|
|
|
|
const auto& info = css::CommonAnimationManager::sLayerAnimationInfo;
|
|
|
|
for (size_t i = 0; i < ArrayLength(info); i++) {
|
|
|
|
auto record = info[i];
|
|
|
|
if (!HasAnimationOfProperty(record.mProperty)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-12-12 01:12:43 +04:00
|
|
|
Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
|
2014-11-17 07:46:00 +03:00
|
|
|
frame, record.mLayerType);
|
2012-12-12 01:12:43 +04:00
|
|
|
if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
if (record.mProperty == eCSSProperty_transform &&
|
|
|
|
!CanThrottleTransformChanges(aTime)) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-12-12 01:12:43 +04:00
|
|
|
}
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
return true;
|
2012-12-12 01:12:43 +04:00
|
|
|
}
|
|
|
|
|
2014-06-27 03:57:12 +04:00
|
|
|
void
|
2014-08-10 11:06:46 +04:00
|
|
|
AnimationPlayerCollection::UpdateAnimationGeneration(
|
2014-06-27 03:57:12 +04:00
|
|
|
nsPresContext* aPresContext)
|
2012-12-12 01:12:43 +04:00
|
|
|
{
|
|
|
|
mAnimationGeneration =
|
2013-07-20 23:14:25 +04:00
|
|
|
aPresContext->RestyleManager()->GetAnimationGeneration();
|
2012-12-12 01:12:43 +04:00
|
|
|
}
|
|
|
|
|
2015-02-17 01:15:03 +03:00
|
|
|
void
|
|
|
|
AnimationPlayerCollection::UpdateCheckGeneration(
|
|
|
|
nsPresContext* aPresContext)
|
|
|
|
{
|
|
|
|
mCheckGeneration =
|
|
|
|
aPresContext->RestyleManager()->GetAnimationGeneration();
|
|
|
|
}
|
|
|
|
|
2014-06-16 22:43:04 +04:00
|
|
|
bool
|
2014-10-02 10:14:13 +04:00
|
|
|
AnimationPlayerCollection::HasCurrentAnimations() const
|
2014-06-16 22:43:04 +04:00
|
|
|
{
|
2014-08-10 11:06:48 +04:00
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
2014-10-02 10:14:13 +04:00
|
|
|
if (mPlayers[playerIdx]->HasCurrentSource()) {
|
2014-06-16 22:43:04 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-02 10:14:13 +04:00
|
|
|
bool
|
2015-04-06 05:53:51 +03:00
|
|
|
AnimationPlayerCollection::HasCurrentAnimationsForProperties(
|
|
|
|
const nsCSSProperty* aProperties,
|
|
|
|
size_t aPropertyCount) const
|
2014-10-02 10:14:13 +04:00
|
|
|
{
|
|
|
|
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
2015-03-27 11:44:38 +03:00
|
|
|
const AnimationPlayer& player = *mPlayers[playerIdx];
|
2015-04-15 02:48:21 +03:00
|
|
|
const KeyframeEffectReadonly* effect = player.GetSource();
|
|
|
|
if (effect &&
|
|
|
|
effect->IsCurrent(player) &&
|
|
|
|
effect->HasAnimationOfProperties(aProperties, aPropertyCount)) {
|
2014-10-02 10:14:13 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-04-12 10:18:43 +04:00
|
|
|
}
|