LCOV - code coverage report
Current view: top level - dom/animation - AnimationEffectReadOnly.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 79 161 49.1 %
Date: 2017-07-14 16:53:18 Functions: 8 19 42.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/AnimationEffectReadOnly.h"
       8             : #include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
       9             : #include "mozilla/AnimationUtils.h"
      10             : #include "mozilla/FloatingPoint.h"
      11             : 
      12             : namespace mozilla {
      13             : namespace dom {
      14             : 
      15             : NS_IMPL_CYCLE_COLLECTION_CLASS(AnimationEffectReadOnly)
      16           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AnimationEffectReadOnly)
      17           0 :   if (tmp->mTiming) {
      18           0 :     tmp->mTiming->Unlink();
      19             :   }
      20           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument, mTiming, mAnimation)
      21           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
      22           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      23             : 
      24           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEffectReadOnly)
      25           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument, mTiming, mAnimation)
      26           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      27             : 
      28           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AnimationEffectReadOnly)
      29             : 
      30           8 : NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffectReadOnly)
      31           6 : NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffectReadOnly)
      32             : 
      33           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffectReadOnly)
      34           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      35           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      36           0 : NS_INTERFACE_MAP_END
      37             : 
      38           2 : AnimationEffectReadOnly::AnimationEffectReadOnly(
      39           2 :   nsIDocument* aDocument, AnimationEffectTimingReadOnly* aTiming)
      40             :   : mDocument(aDocument)
      41           2 :   , mTiming(aTiming)
      42             : {
      43           2 :   MOZ_ASSERT(aTiming);
      44           2 : }
      45             : 
      46             : // https://w3c.github.io/web-animations/#current
      47             : bool
      48          68 : AnimationEffectReadOnly::IsCurrent() const
      49             : {
      50          68 :   if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
      51           4 :     return false;
      52             :   }
      53             : 
      54         128 :   ComputedTiming computedTiming = GetComputedTiming();
      55         128 :   return computedTiming.mPhase == ComputedTiming::AnimationPhase::Before ||
      56         128 :          computedTiming.mPhase == ComputedTiming::AnimationPhase::Active;
      57             : }
      58             : 
      59             : // https://w3c.github.io/web-animations/#in-effect
      60             : bool
      61          58 : AnimationEffectReadOnly::IsInEffect() const
      62             : {
      63         116 :   ComputedTiming computedTiming = GetComputedTiming();
      64         116 :   return !computedTiming.mProgress.IsNull();
      65             : }
      66             : 
      67             : already_AddRefed<AnimationEffectTimingReadOnly>
      68           0 : AnimationEffectReadOnly::Timing()
      69             : {
      70           0 :   RefPtr<AnimationEffectTimingReadOnly> temp(mTiming);
      71           0 :   return temp.forget();
      72             : }
      73             : 
      74             : void
      75           0 : AnimationEffectReadOnly::SetSpecifiedTiming(const TimingParams& aTiming)
      76             : {
      77           0 :   if (mTiming->AsTimingParams() == aTiming) {
      78           0 :     return;
      79             :   }
      80           0 :   mTiming->SetTimingParams(aTiming);
      81           0 :   if (mAnimation) {
      82           0 :     mAnimation->NotifyEffectTimingUpdated();
      83             :   }
      84             :   // For keyframe effects, NotifyEffectTimingUpdated above will eventually cause
      85             :   // KeyframeEffectReadOnly::NotifyAnimationTimingUpdated to be called so it can
      86             :   // update its registration with the target element as necessary.
      87             : }
      88             : 
      89             : ComputedTiming
      90         186 : AnimationEffectReadOnly::GetComputedTimingAt(
      91             :     const Nullable<TimeDuration>& aLocalTime,
      92             :     const TimingParams& aTiming,
      93             :     double aPlaybackRate)
      94             : {
      95         186 :   const StickyTimeDuration zeroDuration;
      96             : 
      97             :   // Always return the same object to benefit from return-value optimization.
      98         186 :   ComputedTiming result;
      99             : 
     100         186 :   if (aTiming.Duration()) {
     101         186 :     MOZ_ASSERT(aTiming.Duration().ref() >= zeroDuration,
     102             :                "Iteration duration should be positive");
     103         186 :     result.mDuration = aTiming.Duration().ref();
     104             :   }
     105             : 
     106         186 :   MOZ_ASSERT(aTiming.Iterations() >= 0.0 && !IsNaN(aTiming.Iterations()),
     107             :              "mIterations should be nonnegative & finite, as ensured by "
     108             :              "ValidateIterations or CSSParser");
     109         186 :   result.mIterations = aTiming.Iterations();
     110             : 
     111         186 :   MOZ_ASSERT(aTiming.IterationStart() >= 0.0,
     112             :              "mIterationStart should be nonnegative, as ensured by "
     113             :              "ValidateIterationStart");
     114         186 :   result.mIterationStart = aTiming.IterationStart();
     115             : 
     116         186 :   result.mActiveDuration = aTiming.ActiveDuration();
     117         186 :   result.mEndTime = aTiming.EndTime();
     118         186 :   result.mFill = aTiming.Fill() == dom::FillMode::Auto ?
     119             :                  dom::FillMode::None :
     120             :                  aTiming.Fill();
     121             : 
     122             :   // The default constructor for ComputedTiming sets all other members to
     123             :   // values consistent with an animation that has not been sampled.
     124         186 :   if (aLocalTime.IsNull()) {
     125          20 :     return result;
     126             :   }
     127         166 :   const TimeDuration& localTime = aLocalTime.Value();
     128             : 
     129             :   StickyTimeDuration beforeActiveBoundary =
     130         332 :     std::max(std::min(StickyTimeDuration(aTiming.Delay()), result.mEndTime),
     131         332 :              zeroDuration);
     132             : 
     133             :   StickyTimeDuration activeAfterBoundary =
     134         332 :     std::max(std::min(StickyTimeDuration(aTiming.Delay() +
     135         166 :                                          result.mActiveDuration),
     136             :                       result.mEndTime),
     137         332 :              zeroDuration);
     138             : 
     139         176 :   if (localTime > activeAfterBoundary ||
     140         166 :       (aPlaybackRate >= 0 && localTime == activeAfterBoundary)) {
     141          10 :     result.mPhase = ComputedTiming::AnimationPhase::After;
     142          10 :     if (!result.FillsForwards()) {
     143             :       // The animation isn't active or filling at this time.
     144          10 :       return result;
     145             :     }
     146           0 :     result.mActiveTime =
     147           0 :       std::max(std::min(StickyTimeDuration(localTime - aTiming.Delay()),
     148             :                         result.mActiveDuration),
     149           0 :                zeroDuration);
     150         156 :   } else if (localTime < beforeActiveBoundary ||
     151           0 :              (aPlaybackRate < 0 && localTime == beforeActiveBoundary)) {
     152           0 :     result.mPhase = ComputedTiming::AnimationPhase::Before;
     153           0 :     if (!result.FillsBackwards()) {
     154             :       // The animation isn't active or filling at this time.
     155           0 :       return result;
     156             :     }
     157             :     result.mActiveTime
     158           0 :       = std::max(StickyTimeDuration(localTime - aTiming.Delay()),
     159           0 :                  zeroDuration);
     160             :   } else {
     161         156 :     MOZ_ASSERT(result.mActiveDuration != zeroDuration,
     162             :                "How can we be in the middle of a zero-duration interval?");
     163         156 :     result.mPhase = ComputedTiming::AnimationPhase::Active;
     164         156 :     result.mActiveTime = localTime - aTiming.Delay();
     165             :   }
     166             : 
     167             :   // Convert active time to a multiple of iterations.
     168             :   // https://w3c.github.io/web-animations/#overall-progress
     169             :   double overallProgress;
     170         156 :   if (result.mDuration == zeroDuration) {
     171           0 :     overallProgress = result.mPhase == ComputedTiming::AnimationPhase::Before
     172           0 :                       ? 0.0
     173             :                       : result.mIterations;
     174             :   } else {
     175         156 :     overallProgress = result.mActiveTime / result.mDuration;
     176             :   }
     177             : 
     178             :   // Factor in iteration start offset.
     179         156 :   if (IsFinite(overallProgress)) {
     180         156 :     overallProgress += result.mIterationStart;
     181             :   }
     182             : 
     183             :   // Determine the 0-based index of the current iteration.
     184             :   // https://w3c.github.io/web-animations/#current-iteration
     185         156 :   result.mCurrentIteration =
     186         156 :     IsInfinite(result.mIterations) &&
     187           0 :       result.mPhase == ComputedTiming::AnimationPhase::After
     188         312 :     ? UINT64_MAX // In GetComputedTimingDictionary(),
     189             :                  // we will convert this into Infinity
     190             :     : static_cast<uint64_t>(overallProgress);
     191             : 
     192             :   // Convert the overall progress to a fraction of a single iteration--the
     193             :   // simply iteration progress.
     194             :   // https://w3c.github.io/web-animations/#simple-iteration-progress
     195         156 :   double progress = IsFinite(overallProgress)
     196         156 :                     ? fmod(overallProgress, 1.0)
     197         156 :                     : fmod(result.mIterationStart, 1.0);
     198             : 
     199             :   // When we finish exactly at the end of an iteration we need to report
     200             :   // the end of the final iteration and not the start of the next iteration.
     201             :   // We *don't* want to do this when we have a zero-iteration animation or
     202             :   // when the animation has been effectively made into a zero-duration animation
     203             :   // using a negative end-delay, however.
     204         312 :   if (result.mPhase == ComputedTiming::AnimationPhase::After &&
     205           0 :       progress == 0.0 &&
     206         156 :       result.mIterations != 0.0 &&
     207           0 :       (result.mActiveTime != zeroDuration ||
     208           0 :        result.mDuration == zeroDuration)) {
     209             :     // The only way we can be in the after phase with a progress of zero and
     210             :     // a current iteration of zero, is if we have a zero iteration count or
     211             :     // were clipped using a negative end delay--both of which we should have
     212             :     // detected above.
     213           0 :     MOZ_ASSERT(result.mCurrentIteration != 0,
     214             :                "Should not have zero current iteration");
     215           0 :     progress = 1.0;
     216           0 :     if (result.mCurrentIteration != UINT64_MAX) {
     217           0 :       result.mCurrentIteration--;
     218             :     }
     219             :   }
     220             : 
     221             :   // Factor in the direction.
     222         156 :   bool thisIterationReverse = false;
     223         156 :   switch (aTiming.Direction()) {
     224             :     case PlaybackDirection::Normal:
     225         156 :       thisIterationReverse = false;
     226         156 :       break;
     227             :     case PlaybackDirection::Reverse:
     228           0 :       thisIterationReverse = true;
     229           0 :       break;
     230             :     case PlaybackDirection::Alternate:
     231           0 :       thisIterationReverse = (result.mCurrentIteration & 1) == 1;
     232           0 :       break;
     233             :     case PlaybackDirection::Alternate_reverse:
     234           0 :       thisIterationReverse = (result.mCurrentIteration & 1) == 0;
     235           0 :       break;
     236             :     default:
     237           0 :       MOZ_ASSERT_UNREACHABLE("Unknown PlaybackDirection type");
     238             :   }
     239         156 :   if (thisIterationReverse) {
     240           0 :     progress = 1.0 - progress;
     241             :   }
     242             : 
     243             :   // Calculate the 'before flag' which we use when applying step timing
     244             :   // functions.
     245         156 :   if ((result.mPhase == ComputedTiming::AnimationPhase::After &&
     246         156 :        thisIterationReverse) ||
     247         156 :       (result.mPhase == ComputedTiming::AnimationPhase::Before &&
     248           0 :        !thisIterationReverse)) {
     249           0 :     result.mBeforeFlag = ComputedTimingFunction::BeforeFlag::Set;
     250             :   }
     251             : 
     252             :   // Apply the easing.
     253         156 :   if (aTiming.TimingFunction()) {
     254           0 :     progress = aTiming.TimingFunction()->GetValue(progress, result.mBeforeFlag);
     255             :   }
     256             : 
     257         156 :   MOZ_ASSERT(IsFinite(progress), "Progress value should be finite");
     258         156 :   result.mProgress.SetValue(progress);
     259         156 :   return result;
     260             : }
     261             : 
     262             : ComputedTiming
     263         186 : AnimationEffectReadOnly::GetComputedTiming(const TimingParams* aTiming) const
     264             : {
     265         186 :   double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
     266         372 :   return GetComputedTimingAt(GetLocalTime(),
     267             :                              aTiming ? *aTiming : SpecifiedTiming(),
     268         558 :                              playbackRate);
     269             : }
     270             : 
     271             : // Helper functions for generating a ComputedTimingProperties dictionary
     272             : static void
     273           0 : GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
     274             :                             const Nullable<TimeDuration>& aLocalTime,
     275             :                             const TimingParams& aTiming,
     276             :                             ComputedTimingProperties& aRetVal)
     277             : {
     278             :   // AnimationEffectTimingProperties
     279           0 :   aRetVal.mDelay = aTiming.Delay().ToMilliseconds();
     280           0 :   aRetVal.mEndDelay = aTiming.EndDelay().ToMilliseconds();
     281           0 :   aRetVal.mFill = aComputedTiming.mFill;
     282           0 :   aRetVal.mIterations = aComputedTiming.mIterations;
     283           0 :   aRetVal.mIterationStart = aComputedTiming.mIterationStart;
     284           0 :   aRetVal.mDuration.SetAsUnrestrictedDouble() =
     285           0 :     aComputedTiming.mDuration.ToMilliseconds();
     286           0 :   aRetVal.mDirection = aTiming.Direction();
     287             : 
     288             :   // ComputedTimingProperties
     289           0 :   aRetVal.mActiveDuration = aComputedTiming.mActiveDuration.ToMilliseconds();
     290           0 :   aRetVal.mEndTime = aComputedTiming.mEndTime.ToMilliseconds();
     291           0 :   aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(aLocalTime);
     292           0 :   aRetVal.mProgress = aComputedTiming.mProgress;
     293             : 
     294           0 :   if (!aRetVal.mProgress.IsNull()) {
     295             :     // Convert the returned currentIteration into Infinity if we set
     296             :     // (uint64_t) aComputedTiming.mCurrentIteration to UINT64_MAX
     297           0 :     double iteration = aComputedTiming.mCurrentIteration == UINT64_MAX
     298           0 :                        ? PositiveInfinity<double>()
     299           0 :                        : static_cast<double>(aComputedTiming.mCurrentIteration);
     300           0 :     aRetVal.mCurrentIteration.SetValue(iteration);
     301             :   }
     302           0 : }
     303             : 
     304             : void
     305           0 : AnimationEffectReadOnly::GetComputedTimingAsDict(
     306             :   ComputedTimingProperties& aRetVal) const
     307             : {
     308           0 :   double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
     309           0 :   const Nullable<TimeDuration> currentTime = GetLocalTime();
     310           0 :   GetComputedTimingDictionary(GetComputedTimingAt(currentTime,
     311             :                                                   SpecifiedTiming(),
     312             :                                                   playbackRate),
     313             :                               currentTime,
     314             :                               SpecifiedTiming(),
     315           0 :                               aRetVal);
     316           0 : }
     317             : 
     318           0 : AnimationEffectReadOnly::~AnimationEffectReadOnly()
     319             : {
     320             :   // mTiming is cycle collected, so we have to do null check first even though
     321             :   // mTiming shouldn't be null during the lifetime of KeyframeEffect.
     322           0 :   if (mTiming) {
     323           0 :     mTiming->Unlink();
     324             :   }
     325           0 : }
     326             : 
     327             : Nullable<TimeDuration>
     328         186 : AnimationEffectReadOnly::GetLocalTime() const
     329             : {
     330             :   // Since the *animation* start time is currently always zero, the local
     331             :   // time is equal to the parent time.
     332         186 :   Nullable<TimeDuration> result;
     333         186 :   if (mAnimation) {
     334         186 :     result = mAnimation->GetCurrentTime();
     335             :   }
     336         186 :   return result;
     337             : }
     338             : 
     339             : } // namespace dom
     340             : } // namespace mozilla

Generated by: LCOV version 1.13