gecko-dev/dom/animation/EffectSet.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

199 lines
6.2 KiB
C++
Raw Normal View History

/* -*- 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/RestyleManager.h"
#include "nsCSSPseudoElements.h" // For PseudoStyleType
#include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild
#include "nsPresContext.h"
#include "nsLayoutUtils.h"
namespace mozilla {
/* static */
void EffectSet::PropertyDtor(void* aObject, nsAtom* 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(const dom::Element* aElement,
PseudoStyleType aPseudoType) {
if (!aElement->MayHaveAnimations()) {
return nullptr;
}
nsAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
return static_cast<EffectSet*>(aElement->GetProperty(propName));
}
/* static */
EffectSet* EffectSet::GetOrCreateEffectSet(dom::Element* aElement,
PseudoStyleType aPseudoType) {
EffectSet* effectSet = GetEffectSet(aElement, aPseudoType);
if (effectSet) {
return effectSet;
}
nsAtom* 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 */
EffectSet* EffectSet::GetEffectSetForFrame(
const nsIFrame* aFrame, const nsCSSPropertyIDSet& aProperties) {
MOZ_ASSERT(aFrame);
// Transform animations are run on the primary frame (but stored on the
// content associated with the style frame).
const nsIFrame* frameToQuery = nullptr;
if (aProperties.IsSubsetOf(nsCSSPropertyIDSet::TransformLikeProperties())) {
// Make sure to return nullptr if we're looking for transform animations on
// the inner table frame.
if (!aFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
return nullptr;
}
frameToQuery = nsLayoutUtils::GetStyleFrame(aFrame);
} else {
MOZ_ASSERT(
!aProperties.Intersects(nsCSSPropertyIDSet::TransformLikeProperties()),
"We should have only transform properties or no transform properties");
// We don't need to explicitly return nullptr when |aFrame| is NOT the style
// frame since there will be no effect set in that case.
frameToQuery = aFrame;
}
Maybe<NonOwningAnimationTarget> target =
EffectCompositor::GetAnimationElementAndPseudoForFrame(frameToQuery);
if (!target) {
return nullptr;
}
return GetEffectSet(target->mElement, target->mPseudoType);
}
/* static */
EffectSet* EffectSet::GetEffectSetForFrame(const nsIFrame* aFrame,
DisplayItemType aDisplayItemType) {
return EffectSet::GetEffectSetForFrame(
aFrame, LayerAnimationInfo::GetCSSPropertiesFor(aDisplayItemType));
}
/* static */
EffectSet* EffectSet::GetEffectSetForStyleFrame(const nsIFrame* aStyleFrame) {
Maybe<NonOwningAnimationTarget> target =
EffectCompositor::GetAnimationElementAndPseudoForFrame(aStyleFrame);
if (!target) {
return nullptr;
}
return GetEffectSet(target->mElement, target->mPseudoType);
}
/* static */
void EffectSet::DestroyEffectSet(dom::Element* aElement,
PseudoStyleType aPseudoType) {
nsAtom* 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) {
mAnimationGeneration =
aPresContext->RestyleManager()->GetAnimationGeneration();
}
/* static */
nsAtom** EffectSet::GetEffectSetPropertyAtoms() {
static nsAtom* effectSetPropertyAtoms[] = {
nsGkAtoms::animationEffectsProperty,
nsGkAtoms::animationEffectsForBeforeProperty,
nsGkAtoms::animationEffectsForAfterProperty,
nsGkAtoms::animationEffectsForMarkerProperty, nullptr};
return effectSetPropertyAtoms;
}
/* static */
nsAtom* EffectSet::GetEffectSetPropertyAtom(PseudoStyleType aPseudoType) {
switch (aPseudoType) {
case PseudoStyleType::NotPseudo:
return nsGkAtoms::animationEffectsProperty;
case PseudoStyleType::before:
return nsGkAtoms::animationEffectsForBeforeProperty;
case PseudoStyleType::after:
return nsGkAtoms::animationEffectsForAfterProperty;
case PseudoStyleType::marker:
return nsGkAtoms::animationEffectsForMarkerProperty;
default:
MOZ_ASSERT_UNREACHABLE(
"Should not try to get animation effects for "
"a pseudo other that :before, :after or ::marker");
return nullptr;
}
}
void EffectSet::AddEffect(dom::KeyframeEffect& aEffect) {
if (!mEffects.EnsureInserted(&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 02:04:04 +00:00
return;
}
MarkCascadeNeedsUpdate();
}
void EffectSet::RemoveEffect(dom::KeyframeEffect& aEffect) {
if (!mEffects.EnsureRemoved(&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 02:04:04 +00:00
return;
}
MarkCascadeNeedsUpdate();
}
} // namespace mozilla