tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ElementAnimationData.cpp (7836B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ElementAnimationData.h"
      8 
      9 #include "mozilla/AnimationCollection.h"
     10 #include "mozilla/AnimationUtils.h"
     11 #include "mozilla/EffectSet.h"
     12 #include "mozilla/TimelineCollection.h"
     13 #include "mozilla/dom/CSSAnimation.h"
     14 #include "mozilla/dom/CSSTransition.h"
     15 #include "mozilla/dom/ScrollTimeline.h"
     16 #include "mozilla/dom/ViewTimeline.h"
     17 
     18 namespace mozilla {
     19 
     20 const ElementAnimationData::PerElementOrPseudoData*
     21 ElementAnimationData::GetPseudoData(const PseudoStyleRequest& aRequest) const {
     22  MOZ_ASSERT(!aRequest.IsNotPseudo(), "Only for pseudo-elements");
     23  MOZ_ASSERT(AnimationUtils::IsSupportedPseudoForAnimations(aRequest.mType));
     24 
     25  auto entry = mPseudoData.Lookup(aRequest);
     26  if (!entry) {
     27    return nullptr;
     28  }
     29  MOZ_ASSERT(*entry, "Should always have a valid UniquePtr");
     30  return entry->get();
     31 }
     32 
     33 ElementAnimationData::PerElementOrPseudoData&
     34 ElementAnimationData::GetOrCreatePseudoData(
     35    const PseudoStyleRequest& aRequest) {
     36  MOZ_ASSERT(!aRequest.IsNotPseudo(), "Only for pseudo-elements");
     37  MOZ_ASSERT(AnimationUtils::IsSupportedPseudoForAnimations(aRequest.mType));
     38 
     39  UniquePtr<PerElementOrPseudoData>& data = mPseudoData.LookupOrInsertWith(
     40      aRequest, [&] { return MakeUnique<PerElementOrPseudoData>(); });
     41  MOZ_ASSERT(data);
     42  return *data;
     43 }
     44 
     45 void ElementAnimationData::Traverse(nsCycleCollectionTraversalCallback& cb) {
     46  mElementData.Traverse(cb);
     47  for (auto& data : mPseudoData.Values()) {
     48    data->Traverse(cb);
     49  }
     50 }
     51 
     52 void ElementAnimationData::ClearAllAnimationCollections() {
     53  mElementData.mAnimations = nullptr;
     54  mElementData.mTransitions = nullptr;
     55  mElementData.mScrollTimelines = nullptr;
     56  mElementData.mViewTimelines = nullptr;
     57  ClearAllPseudos(false);
     58 }
     59 
     60 void ElementAnimationData::ClearAllPseudos(bool aOnlyViewTransitions) {
     61  if (mPseudoData.IsEmpty()) {
     62    return;
     63  }
     64 
     65  mIsClearingPseudoData = true;
     66  for (auto iter = mPseudoData.Iter(); !iter.Done(); iter.Next()) {
     67    const auto& data = iter.Data();
     68    MOZ_ASSERT(data);
     69 
     70    if (aOnlyViewTransitions && !iter.Key().IsViewTransition()) {
     71      continue;
     72    }
     73 
     74    // Note: We cannot remove EffectSet because we expect there is a valid
     75    // EffectSet when unregistering the target.
     76    // (See KeyframeEffect::UnregisterTarget() for more details).
     77    // So we rely on EffectSet::Destroy() to clear it.
     78    data->mAnimations = nullptr;
     79    data->mTransitions = nullptr;
     80    data->mScrollTimelines = nullptr;
     81    data->mViewTimelines = nullptr;
     82 
     83    if (data->IsEmpty()) {
     84      iter.Remove();
     85    }
     86  }
     87  mIsClearingPseudoData = false;
     88 }
     89 
     90 void ElementAnimationData::MaybeClearEntry(
     91    PseudoData::LookupResult<PseudoData&>&& aEntry) {
     92  if (mIsClearingPseudoData || !aEntry || !aEntry.Data()->IsEmpty()) {
     93    return;
     94  }
     95  UniquePtr<PerElementOrPseudoData> temp(std::move(*aEntry));
     96  aEntry.Remove();
     97 }
     98 
     99 template <typename Fn>
    100 void ElementAnimationData::WithDataForRemoval(
    101    const PseudoStyleRequest& aRequest, Fn&& aFn) {
    102  if (aRequest.IsNotPseudo()) {
    103    aFn(mElementData);
    104    return;
    105  }
    106  auto entry = mPseudoData.Lookup(aRequest);
    107  if (!entry) {
    108    return;
    109  }
    110  aFn(**entry);
    111  MaybeClearEntry(std::move(entry));
    112 }
    113 
    114 void ElementAnimationData::ClearEffectSetFor(
    115    const PseudoStyleRequest& aRequest) {
    116  WithDataForRemoval(aRequest, [](PerElementOrPseudoData& aData) {
    117    aData.mEffectSet = nullptr;
    118  });
    119 }
    120 
    121 void ElementAnimationData::ClearTransitionCollectionFor(
    122    const PseudoStyleRequest& aRequest) {
    123  if (aRequest.IsNotPseudo()) {
    124    mElementData.mTransitions = nullptr;
    125    return;
    126  }
    127 
    128  auto entry = mPseudoData.Lookup(aRequest);
    129  if (!entry || !entry.Data()->mTransitions) {
    130    return;
    131  }
    132  // If a KeyframeEffect associated with only the animation in the collection,
    133  // nullifying the collection may call ClearEffectSetFor(), which may clear the
    134  // entry if all empty. Therefore, we move the collection out of the data
    135  // first, and destroy the collection when leaving the function, to make sure
    136  // |entry| is still valid when calling MaybeClearEntry().
    137  // Note: It seems MaybeClearEntry() here may be redundant because we always
    138  // rely on ClearEffectSetFor() to clear the entry. However, we still call it
    139  // just in case.
    140  auto autoRemoved(std::move(entry.Data()->mTransitions));
    141  MaybeClearEntry(std::move(entry));
    142 }
    143 
    144 void ElementAnimationData::ClearAnimationCollectionFor(
    145    const PseudoStyleRequest& aRequest) {
    146  if (aRequest.IsNotPseudo()) {
    147    mElementData.mAnimations = nullptr;
    148    return;
    149  }
    150 
    151  auto entry = mPseudoData.Lookup(aRequest);
    152  if (!entry || !entry.Data()->mAnimations) {
    153    return;
    154  }
    155 
    156  // If a KeyframeEffect associated with only the animation in the collection,
    157  // nullifying the collection may call ClearEffectSetFor(), which may clear the
    158  // entry if all empty. Therefore, we move the collection out of the data
    159  // first, and destroy the collection when leaving the function, to make sure
    160  // |entry| is still valid when calling MaybeClearEntry().
    161  // Note: It seems MaybeClearEntry() here may be redundant because we always
    162  // rely on ClearEffectSetFor() to clear the entry. However, we still call it
    163  // just in case.
    164  auto autoRemoved(std::move(entry.Data()->mAnimations));
    165  MaybeClearEntry(std::move(entry));
    166 }
    167 
    168 void ElementAnimationData::ClearScrollTimelineCollectionFor(
    169    const PseudoStyleRequest& aRequest) {
    170  WithDataForRemoval(aRequest, [](PerElementOrPseudoData& aData) {
    171    aData.mScrollTimelines = nullptr;
    172  });
    173 }
    174 
    175 void ElementAnimationData::ClearViewTimelineCollectionFor(
    176    const PseudoStyleRequest& aRequest) {
    177  WithDataForRemoval(aRequest, [](PerElementOrPseudoData& aData) {
    178    aData.mViewTimelines = nullptr;
    179  });
    180 }
    181 
    182 ElementAnimationData::PerElementOrPseudoData::PerElementOrPseudoData() =
    183    default;
    184 ElementAnimationData::PerElementOrPseudoData::~PerElementOrPseudoData() =
    185    default;
    186 
    187 void ElementAnimationData::PerElementOrPseudoData::Traverse(
    188    nsCycleCollectionTraversalCallback& cb) {
    189  // We only care about mEffectSet. The animation collections are managed by the
    190  // pres context and go away when presentation of the document goes away.
    191  if (mEffectSet) {
    192    mEffectSet->Traverse(cb);
    193  }
    194 }
    195 
    196 EffectSet& ElementAnimationData::PerElementOrPseudoData::DoEnsureEffectSet() {
    197  MOZ_ASSERT(!mEffectSet);
    198  mEffectSet = MakeUnique<EffectSet>();
    199  return *mEffectSet;
    200 }
    201 
    202 CSSTransitionCollection&
    203 ElementAnimationData::PerElementOrPseudoData::DoEnsureTransitions(
    204    dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
    205  MOZ_ASSERT(!mTransitions);
    206  mTransitions = MakeUnique<CSSTransitionCollection>(aOwner, aRequest);
    207  return *mTransitions;
    208 }
    209 
    210 CSSAnimationCollection&
    211 ElementAnimationData::PerElementOrPseudoData::DoEnsureAnimations(
    212    dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
    213  MOZ_ASSERT(!mAnimations);
    214  mAnimations = MakeUnique<CSSAnimationCollection>(aOwner, aRequest);
    215  return *mAnimations;
    216 }
    217 
    218 ScrollTimelineCollection&
    219 ElementAnimationData::PerElementOrPseudoData::DoEnsureScrollTimelines(
    220    dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
    221  MOZ_ASSERT(!mScrollTimelines);
    222  mScrollTimelines = MakeUnique<ScrollTimelineCollection>(aOwner, aRequest);
    223  return *mScrollTimelines;
    224 }
    225 
    226 ViewTimelineCollection&
    227 ElementAnimationData::PerElementOrPseudoData::DoEnsureViewTimelines(
    228    dom::Element& aOwner, const PseudoStyleRequest& aRequest) {
    229  MOZ_ASSERT(!mViewTimelines);
    230  mViewTimelines = MakeUnique<ViewTimelineCollection>(aOwner, aRequest);
    231  return *mViewTimelines;
    232 }
    233 
    234 }  // namespace mozilla