/* 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/. */
#ifndef nsAnimationManager_h_
#define nsAnimationManager_h_
#include "AnimationCommon.h"
#include "mozilla/Keyframe.h"
#include "mozilla/dom/CSSAnimation.h"
#include "nsISupportsImpl.h"
#include "nsTHashSet.h"
class ServoCSSAnimationBuilder;
struct nsStyleUIReset;
namespace mozilla {
class ComputedStyle;
struct NonOwningAnimationTarget;
struct PseudoStyleRequest;
}
/* namespace mozilla */
class nsAnimationManager final
: public mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation> {
public:
using TimelineNamesToAnimationMap =
nsTHashMap<RefPtr<
const nsAtom>,
nsTArray<RefPtr<mozilla::dom::CSSAnimation>>>;
explicit nsAnimationManager(nsPresContext* aPresContext)
: mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation>(
aPresContext) {}
typedef mozilla::AnimationCollection<mozilla::dom::CSSAnimation>
CSSAnimationCollection;
typedef nsTArray<RefPtr<mozilla::dom::CSSAnimation>>
OwningCSSAnimationPtrArray;
~nsAnimationManager() override =
default;
/**
* This function does the same thing as the above UpdateAnimations()
* but with servo's computed values.
*/
void UpdateAnimations(mozilla::dom::Element* aElement,
const mozilla::PseudoStyleRequest& aPseudoRequest,
const mozilla::ComputedStyle* aComputedValues);
void RemoveNamedTimelineAnimation(
const nsAtom* aName,
mozilla::dom::CSSAnimation* aAnimation);
void UpdateNamedTimelineAnimations(
const nsTArray<RefPtr<
const nsAtom>>& aChanged);
void UpdateAllNamedTimelineAnimations();
// Utility function to walk through |aIter| to find the Keyframe with
// matching offset and timing function but stopping as soon as the offset
// differs from |aOffset| (i.e. it assumes a sorted iterator for double
// offsets). For TimelineRangeOffset, see the comments in the loop.
//
// If a matching Keyframe is found,
// Returns true and sets |aIndex| to the index of the matching Keyframe
// within |aIter|.
//
// If no matching Keyframe is found,
// Returns false and sets |aIndex| to the index in the iterator of the
// first Keyframe with an offset differing to |aOffset| or, if the end
// of the iterator is reached, sets |aIndex| to the index after the last
// Keyframe.
template <
class IterType>
static bool FindMatchingKeyframe(
IterType&& aIter,
const mozilla::Keyframe::OffsetType& aOffset,
const mozilla::StyleComputedTimingFunction& aTimingFunctionToMatch,
mozilla::dom::CompositeOperationOrAuto aCompositionToMatch,
size_t& aIndex) {
aIndex =
0;
for (mozilla::Keyframe& keyframe : aIter) {
if (keyframe.mOffset.value() != aOffset) {
// There is an assumption that we handle keyframes with double offsets
// first, and they are in sorted order. So when we are searching for a
// double offset and the offset is different from the current
// |keyframe|, it must be a non-existing Keyframe.
if (aOffset.IsPercentageOffset()) {
break;
}
// There is an assumption that we handle keyframes with
// TimelineRangeOffset after we insert all the keyframes with double
// offsets, and the Keyframe with TimelineRangeOffset should be put
// after the Keyframes with double offsets. In this case, we search for
// the TimelineRangeOffset in the reversed order of Keyframes.
// Therefore, if current |keyframe| is is double offset, |offset| must
// not exist.
if (keyframe.mOffset->IsPercentageOffset()) {
break;
}
++aIndex;
continue;
}
const bool matches = [&] {
if (keyframe.mComposite != aCompositionToMatch) {
return false;
}
return keyframe.mTimingFunction
? *keyframe.mTimingFunction == aTimingFunctionToMatch
: aTimingFunctionToMatch.IsLinearKeyword();
}();
if (matches) {
return true;
}
++aIndex;
}
return false;
}
bool AnimationMayBeReferenced(nsAtom* aName)
const {
return mMaybeReferencedAnimations.Contains(aName);
}
private:
// This includes all animation names referenced regardless of whether a
// corresponding `@keyframes` rule is available.
//
// It may contain names which are no longer referenced, but it should always
// contain names which are currently referenced, so that it is usable for
// style invalidation.
nsTHashSet<RefPtr<nsAtom>> mMaybeReferencedAnimations;
// Animations that refer to a timeline by name. This is necessary for
// invalidating such animations, because the timeline referred to by
// that name for the animation target may change.
// Note that only scroll and view timelines can be named.
// Also note that we represent `animation-timeline: none` as a named
// timeline with an empty name, which is not tracked in this hashmap.
TimelineNamesToAnimationMap mAnimationsWithNamedTimeline;
void DoUpdateAnimations(
const mozilla::NonOwningAnimationTarget& aTarget,
const nsStyleUIReset& aStyle,
ServoCSSAnimationBuilder& aBuilder);
};
#endif /* !defined(nsAnimationManager_h_) */