gecko-dev/dom/animation/EffectSet.cpp

202 строки
5.6 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EffectSet.h"
#include "mozilla/dom/Element.h" // For Element
#include "mozilla/RestyleManagerHandle.h"
#include "mozilla/RestyleManagerHandleInlines.h"
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild
#include "nsPresContext.h"
#include "nsLayoutUtils.h"
namespace mozilla {
/* static */ void
EffectSet::PropertyDtor(void* aObject, nsIAtom* aPropertyName,
void* aPropertyValue, void* aData)
{
EffectSet* effectSet = static_cast<EffectSet*>(aPropertyValue);
#ifdef DEBUG
MOZ_ASSERT(!effectSet->mCalledPropertyDtor, "Should not call dtor twice");
effectSet->mCalledPropertyDtor = true;
#endif
delete effectSet;
}
void
EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback)
{
for (auto iter = mEffects.Iter(); !iter.Done(); iter.Next()) {
CycleCollectionNoteChild(aCallback, iter.Get()->GetKey(),
"EffectSet::mEffects[]", aCallback.Flags());
}
}
/* static */ EffectSet*
EffectSet::GetEffectSet(dom::Element* aElement,
CSSPseudoElementType aPseudoType)
{
nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
return static_cast<EffectSet*>(aElement->GetProperty(propName));
}
/* static */ EffectSet*
EffectSet::GetEffectSet(const nsIFrame* aFrame)
{
nsIContent* content = aFrame->GetContent();
if (!content) {
return nullptr;
}
nsIAtom* propName;
if (aFrame->IsGeneratedContentFrame()) {
nsIFrame* parent = aFrame->GetParent();
if (parent->IsGeneratedContentFrame()) {
return nullptr;
}
nsIAtom* name = content->NodeInfo()->NameAtom();
if (name == nsGkAtoms::mozgeneratedcontentbefore) {
propName = nsGkAtoms::animationEffectsForBeforeProperty;
} else if (name == nsGkAtoms::mozgeneratedcontentafter) {
propName = nsGkAtoms::animationEffectsForAfterProperty;
} else {
return nullptr;
}
content = content->GetParent();
if (!content) {
return nullptr;
}
} else {
if (nsLayoutUtils::GetStyleFrame(content) != aFrame) {
// The effects associated with an element are for its primary frame.
return nullptr;
}
propName = nsGkAtoms::animationEffectsProperty;
}
if (!content->MayHaveAnimations()) {
return nullptr;
}
return static_cast<EffectSet*>(content->GetProperty(propName));
}
/* static */ EffectSet*
EffectSet::GetOrCreateEffectSet(dom::Element* aElement,
CSSPseudoElementType aPseudoType)
{
EffectSet* effectSet = GetEffectSet(aElement, aPseudoType);
if (effectSet) {
return effectSet;
}
nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
effectSet = new EffectSet();
nsresult rv = aElement->SetProperty(propName, effectSet,
&EffectSet::PropertyDtor, true);
if (NS_FAILED(rv)) {
NS_WARNING("SetProperty failed");
// The set must be destroyed via PropertyDtor, otherwise
// mCalledPropertyDtor assertion is triggered in destructor.
EffectSet::PropertyDtor(aElement, propName, effectSet, nullptr);
return nullptr;
}
aElement->SetMayHaveAnimations();
return effectSet;
}
/* static */ void
EffectSet::DestroyEffectSet(dom::Element* aElement,
CSSPseudoElementType aPseudoType)
{
nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
EffectSet* effectSet =
static_cast<EffectSet*>(aElement->GetProperty(propName));
if (!effectSet) {
return;
}
MOZ_ASSERT(!effectSet->IsBeingEnumerated(),
"Should not destroy an effect set while it is being enumerated");
effectSet = nullptr;
aElement->DeleteProperty(propName);
}
void
EffectSet::UpdateAnimationGeneration(nsPresContext* aPresContext)
{
MOZ_ASSERT(aPresContext->RestyleManager()->IsGecko(),
"stylo: Servo-backed style system should not be using "
"EffectSet");
mAnimationGeneration =
aPresContext->RestyleManager()->AsGecko()->GetAnimationGeneration();
}
/* static */ nsIAtom**
EffectSet::GetEffectSetPropertyAtoms()
{
static nsIAtom* effectSetPropertyAtoms[] =
{
nsGkAtoms::animationEffectsProperty,
nsGkAtoms::animationEffectsForBeforeProperty,
nsGkAtoms::animationEffectsForAfterProperty,
nullptr
};
return effectSetPropertyAtoms;
}
/* static */ nsIAtom*
EffectSet::GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType)
{
switch (aPseudoType) {
case CSSPseudoElementType::NotPseudo:
return nsGkAtoms::animationEffectsProperty;
case CSSPseudoElementType::before:
return nsGkAtoms::animationEffectsForBeforeProperty;
case CSSPseudoElementType::after:
return nsGkAtoms::animationEffectsForAfterProperty;
default:
NS_NOTREACHED("Should not try to get animation effects for a pseudo "
"other that :before or :after");
return nullptr;
}
}
void
EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect)
{
Bug 1228229 part 4 - Add a flag to EffectSet to mark when the cascade needs to be updated; r=dbaron There are three situations when the cascade results of effects needs to be updated. 1. The sets of effects (animations) has changed. 2. One or more effects have changed their "in effect" status. 3. Other style properties affecting the element have changing meaning that animations applied at the animations-level of the cascade may now be overridden or become active again. We want to detect these situations so we can avoid updating the cascade when none of these possibilities exist. Currently we handle case 1 by calling UpdateCascadeResults at the appropriate point in nsAnimationManager and nsTransitionManager when we build animations/transtiions. Case 2 only affects animations (since whether transitions are in effect or not makes no difference to the cascade--they have a lower "composite order" than animations and never overlap with each other so they can't override anything). As a result, we handle it by adding a flag to CSSAnimation to track when an animation was in effect last time we checked or not. For case 3, we take care to call UpdateCascadeResults when the style context changed in nsAnimationManager::CheckAnimationRule (called from nsStyleSet::GetContext). We want to generalize this detection to handle script-generated animations too. In order to do that this patch introduces a flag to EffectSet that we will use to mark when the cascade needs to be updated in cases 1 and 2. This patch also sets the flag when we detect case 1. A subsequent patch sets the flag for case 2. Case 3 is more difficult to detect and so we simply maintain the existing behavior of making nsAnimationManager::CheckAnimationRule unconditionally update the cascade without checking if the "needs update" flag is set. --HG-- extra : rebase_source : fc56b1bb5a98ae78b93a179c7a3b8af4724a06a1
2016-01-06 05:04:04 +03:00
if (mEffects.Contains(&aEffect)) {
return;
}
mEffects.PutEntry(&aEffect);
Bug 1228229 part 4 - Add a flag to EffectSet to mark when the cascade needs to be updated; r=dbaron There are three situations when the cascade results of effects needs to be updated. 1. The sets of effects (animations) has changed. 2. One or more effects have changed their "in effect" status. 3. Other style properties affecting the element have changing meaning that animations applied at the animations-level of the cascade may now be overridden or become active again. We want to detect these situations so we can avoid updating the cascade when none of these possibilities exist. Currently we handle case 1 by calling UpdateCascadeResults at the appropriate point in nsAnimationManager and nsTransitionManager when we build animations/transtiions. Case 2 only affects animations (since whether transitions are in effect or not makes no difference to the cascade--they have a lower "composite order" than animations and never overlap with each other so they can't override anything). As a result, we handle it by adding a flag to CSSAnimation to track when an animation was in effect last time we checked or not. For case 3, we take care to call UpdateCascadeResults when the style context changed in nsAnimationManager::CheckAnimationRule (called from nsStyleSet::GetContext). We want to generalize this detection to handle script-generated animations too. In order to do that this patch introduces a flag to EffectSet that we will use to mark when the cascade needs to be updated in cases 1 and 2. This patch also sets the flag when we detect case 1. A subsequent patch sets the flag for case 2. Case 3 is more difficult to detect and so we simply maintain the existing behavior of making nsAnimationManager::CheckAnimationRule unconditionally update the cascade without checking if the "needs update" flag is set. --HG-- extra : rebase_source : fc56b1bb5a98ae78b93a179c7a3b8af4724a06a1
2016-01-06 05:04:04 +03:00
MarkCascadeNeedsUpdate();
}
void
EffectSet::RemoveEffect(dom::KeyframeEffectReadOnly& aEffect)
{
Bug 1228229 part 4 - Add a flag to EffectSet to mark when the cascade needs to be updated; r=dbaron There are three situations when the cascade results of effects needs to be updated. 1. The sets of effects (animations) has changed. 2. One or more effects have changed their "in effect" status. 3. Other style properties affecting the element have changing meaning that animations applied at the animations-level of the cascade may now be overridden or become active again. We want to detect these situations so we can avoid updating the cascade when none of these possibilities exist. Currently we handle case 1 by calling UpdateCascadeResults at the appropriate point in nsAnimationManager and nsTransitionManager when we build animations/transtiions. Case 2 only affects animations (since whether transitions are in effect or not makes no difference to the cascade--they have a lower "composite order" than animations and never overlap with each other so they can't override anything). As a result, we handle it by adding a flag to CSSAnimation to track when an animation was in effect last time we checked or not. For case 3, we take care to call UpdateCascadeResults when the style context changed in nsAnimationManager::CheckAnimationRule (called from nsStyleSet::GetContext). We want to generalize this detection to handle script-generated animations too. In order to do that this patch introduces a flag to EffectSet that we will use to mark when the cascade needs to be updated in cases 1 and 2. This patch also sets the flag when we detect case 1. A subsequent patch sets the flag for case 2. Case 3 is more difficult to detect and so we simply maintain the existing behavior of making nsAnimationManager::CheckAnimationRule unconditionally update the cascade without checking if the "needs update" flag is set. --HG-- extra : rebase_source : fc56b1bb5a98ae78b93a179c7a3b8af4724a06a1
2016-01-06 05:04:04 +03:00
if (!mEffects.Contains(&aEffect)) {
return;
}
mEffects.RemoveEntry(&aEffect);
Bug 1228229 part 4 - Add a flag to EffectSet to mark when the cascade needs to be updated; r=dbaron There are three situations when the cascade results of effects needs to be updated. 1. The sets of effects (animations) has changed. 2. One or more effects have changed their "in effect" status. 3. Other style properties affecting the element have changing meaning that animations applied at the animations-level of the cascade may now be overridden or become active again. We want to detect these situations so we can avoid updating the cascade when none of these possibilities exist. Currently we handle case 1 by calling UpdateCascadeResults at the appropriate point in nsAnimationManager and nsTransitionManager when we build animations/transtiions. Case 2 only affects animations (since whether transitions are in effect or not makes no difference to the cascade--they have a lower "composite order" than animations and never overlap with each other so they can't override anything). As a result, we handle it by adding a flag to CSSAnimation to track when an animation was in effect last time we checked or not. For case 3, we take care to call UpdateCascadeResults when the style context changed in nsAnimationManager::CheckAnimationRule (called from nsStyleSet::GetContext). We want to generalize this detection to handle script-generated animations too. In order to do that this patch introduces a flag to EffectSet that we will use to mark when the cascade needs to be updated in cases 1 and 2. This patch also sets the flag when we detect case 1. A subsequent patch sets the flag for case 2. Case 3 is more difficult to detect and so we simply maintain the existing behavior of making nsAnimationManager::CheckAnimationRule unconditionally update the cascade without checking if the "needs update" flag is set. --HG-- extra : rebase_source : fc56b1bb5a98ae78b93a179c7a3b8af4724a06a1
2016-01-06 05:04:04 +03:00
MarkCascadeNeedsUpdate();
}
} // namespace mozilla