Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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/. */
#ifndef mozilla_ElementAnimationData_h
#define mozilla_ElementAnimationData_h
#include "mozilla/PseudoStyleType.h"
#include "mozilla/UniquePtr.h"
#include "nsTHashMap.h"
class nsCycleCollectionTraversalCallback;
namespace mozilla {
class EffectSet;
template <typename Animation>
class AnimationCollection;
template <typename TimelineType>
class TimelineCollection;
namespace dom {
class Element;
class CSSAnimation;
class CSSTransition;
class ScrollTimeline;
class ViewTimeline;
} // namespace dom
using CSSAnimationCollection = AnimationCollection<dom::CSSAnimation>;
using CSSTransitionCollection = AnimationCollection<dom::CSSTransition>;
using ScrollTimelineCollection = TimelineCollection<dom::ScrollTimeline>;
using ViewTimelineCollection = TimelineCollection<dom::ViewTimeline>;
// The animation data for a given element (and its pseudo-elements).
class ElementAnimationData {
struct PerElementOrPseudoData {
UniquePtr<EffectSet> mEffectSet;
UniquePtr<CSSAnimationCollection> mAnimations;
UniquePtr<CSSTransitionCollection> mTransitions;
// Note: scroll-timeline-name is applied to elements which could be
// scroll containers, or replaced elements. view-timeline-name is applied to
// all elements. However, the named timeline is referenceable in
// animation-timeline by the tree order scope.
//
// So it should be fine to create timeline objects only on the elements and
// pseudo elements which support animations.
//
// Note: TimelineCollection owns and manages the named progress timeline
// generated by specifying scroll-timeline-name property and
// view-timeline-name property on this element. However, the anonymous
// progress timelines (e.g. animation-timeline:scroll()) are owned by
// Animation objects only.
UniquePtr<ScrollTimelineCollection> mScrollTimelines;
UniquePtr<ViewTimelineCollection> mViewTimelines;
PerElementOrPseudoData();
~PerElementOrPseudoData();
EffectSet& DoEnsureEffectSet();
CSSTransitionCollection& DoEnsureTransitions(dom::Element&,
const PseudoStyleRequest&);
CSSAnimationCollection& DoEnsureAnimations(dom::Element&,
const PseudoStyleRequest&);
ScrollTimelineCollection& DoEnsureScrollTimelines(
dom::Element&, const PseudoStyleRequest&);
ViewTimelineCollection& DoEnsureViewTimelines(dom::Element&,
const PseudoStyleRequest&);
bool IsEmpty() const {
return !mEffectSet && !mAnimations && !mTransitions &&
!mScrollTimelines && !mViewTimelines;
}
void Traverse(nsCycleCollectionTraversalCallback&);
};
PerElementOrPseudoData mElementData;
using PseudoData =
nsTHashMap<PseudoStyleRequestHashKey, UniquePtr<PerElementOrPseudoData>>;
PseudoData mPseudoData;
// Avoid remove hash entry while other people are still using it.
bool mIsClearingPseudoData = false;
const PerElementOrPseudoData* GetData(
const PseudoStyleRequest& aRequest) const {
if (aRequest.mType != PseudoStyleType::NotPseudo) {
return GetPseudoData(aRequest);
}
return &mElementData;
}
PerElementOrPseudoData& GetOrCreateData(const PseudoStyleRequest& aRequest) {
if (aRequest.mType != PseudoStyleType::NotPseudo) {
return GetOrCreatePseudoData(aRequest);
}
return mElementData;
}
const PerElementOrPseudoData* GetPseudoData(
const PseudoStyleRequest& aRequest) const;
PerElementOrPseudoData& GetOrCreatePseudoData(
const PseudoStyleRequest& aRequest);
void MaybeClearEntry(PseudoData::LookupResult<PseudoData&>&& aEntry);
// |aFn| is the removal function which accepts only |PerElementOrPseudoData&|
// as the parameter.
template <typename Fn>
void WithDataForRemoval(const PseudoStyleRequest& aRequest, Fn&& aFn);
public:
void Traverse(nsCycleCollectionTraversalCallback&);
void ClearAllAnimationCollections();
void ClearAllPseudos(bool aOnlyViewTransitions);
void ClearViewTransitionPseudos() { ClearAllPseudos(true); }
EffectSet* GetEffectSetFor(const PseudoStyleRequest& aRequest) const {
if (auto* data = GetData(aRequest)) {
return data->mEffectSet.get();
}
return nullptr;
}
void ClearEffectSetFor(const PseudoStyleRequest& aRequest);
EffectSet& EnsureEffectSetFor(const PseudoStyleRequest& aRequest) {
auto& data = GetOrCreateData(aRequest);
if (auto* set = data.mEffectSet.get()) {
return *set;
}
return data.DoEnsureEffectSet();
}
CSSTransitionCollection* GetTransitionCollection(
const PseudoStyleRequest& aRequest) const {
if (auto* data = GetData(aRequest)) {
return data->mTransitions.get();
}
return nullptr;
}
void ClearTransitionCollectionFor(const PseudoStyleRequest& aRequest);
CSSTransitionCollection& EnsureTransitionCollection(
dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
auto& data = GetOrCreateData(aRequest);
if (auto* collection = data.mTransitions.get()) {
return *collection;
}
return data.DoEnsureTransitions(aOwner, aRequest);
}
CSSAnimationCollection* GetAnimationCollection(
const PseudoStyleRequest& aRequest) const {
if (auto* data = GetData(aRequest)) {
return data->mAnimations.get();
}
return nullptr;
}
void ClearAnimationCollectionFor(const PseudoStyleRequest& aRequest);
CSSAnimationCollection& EnsureAnimationCollection(
dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
auto& data = GetOrCreateData(aRequest);
if (auto* collection = data.mAnimations.get()) {
return *collection;
}
return data.DoEnsureAnimations(aOwner, aRequest);
}
ScrollTimelineCollection* GetScrollTimelineCollection(
const PseudoStyleRequest& aRequest) const {
if (auto* data = GetData(aRequest)) {
return data->mScrollTimelines.get();
}
return nullptr;
}
void ClearScrollTimelineCollectionFor(const PseudoStyleRequest& aRequest);
ScrollTimelineCollection& EnsureScrollTimelineCollection(
dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
auto& data = GetOrCreateData(aRequest);
if (auto* collection = data.mScrollTimelines.get()) {
return *collection;
}
return data.DoEnsureScrollTimelines(aOwner, aRequest);
}
ViewTimelineCollection* GetViewTimelineCollection(
const PseudoStyleRequest& aRequest) const {
if (auto* data = GetData(aRequest)) {
return data->mViewTimelines.get();
}
return nullptr;
}
void ClearViewTimelineCollectionFor(const PseudoStyleRequest& aRequest);
ViewTimelineCollection& EnsureViewTimelineCollection(
dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
auto& data = GetOrCreateData(aRequest);
if (auto* collection = data.mViewTimelines.get()) {
return *collection;
}
return data.DoEnsureViewTimelines(aOwner, aRequest);
}
ElementAnimationData() = default;
};
} // namespace mozilla
#endif