LCOV - code coverage report
Current view: top level - dom/animation - PendingAnimationTracker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 29 68 42.6 %
Date: 2017-07-14 16:53:18 Functions: 5 14 35.7 %
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 "PendingAnimationTracker.h"
       8             : 
       9             : #include "mozilla/dom/AnimationTimeline.h"
      10             : #include "nsIFrame.h"
      11             : #include "nsIPresShell.h"
      12             : 
      13             : using namespace mozilla;
      14             : 
      15             : namespace mozilla {
      16             : 
      17           0 : NS_IMPL_CYCLE_COLLECTION(PendingAnimationTracker,
      18             :                          mPlayPendingSet,
      19             :                          mPausePendingSet,
      20             :                          mDocument)
      21             : 
      22           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingAnimationTracker, AddRef)
      23           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingAnimationTracker, Release)
      24             : 
      25             : void
      26           2 : PendingAnimationTracker::AddPending(dom::Animation& aAnimation,
      27             :                                     AnimationSet& aSet)
      28             : {
      29           2 :   aSet.PutEntry(&aAnimation);
      30             : 
      31             :   // Schedule a paint. Otherwise animations that don't trigger a paint by
      32             :   // themselves (e.g. CSS animations with an empty keyframes rule) won't
      33             :   // start until something else paints.
      34           2 :   EnsurePaintIsScheduled();
      35           2 : }
      36             : 
      37             : void
      38           0 : PendingAnimationTracker::RemovePending(dom::Animation& aAnimation,
      39             :                                        AnimationSet& aSet)
      40             : {
      41           0 :   aSet.RemoveEntry(&aAnimation);
      42           0 : }
      43             : 
      44             : bool
      45          20 : PendingAnimationTracker::IsWaiting(const dom::Animation& aAnimation,
      46             :                                    const AnimationSet& aSet) const
      47             : {
      48          20 :   return aSet.Contains(const_cast<dom::Animation*>(&aAnimation));
      49             : }
      50             : 
      51             : void
      52          24 : PendingAnimationTracker::TriggerPendingAnimationsOnNextTick(const TimeStamp&
      53             :                                                         aReadyTime)
      54             : {
      55          48 :   auto triggerAnimationsAtReadyTime = [aReadyTime](AnimationSet& aAnimationSet)
      56             :   {
      57          50 :     for (auto iter = aAnimationSet.Iter(); !iter.Done(); iter.Next()) {
      58           2 :       dom::Animation* animation = iter.Get()->GetKey();
      59           2 :       dom::AnimationTimeline* timeline = animation->GetTimeline();
      60             : 
      61             :       // If the animation does not have a timeline, just drop it from the map.
      62             :       // The animation will detect that it is not being tracked and will trigger
      63             :       // itself on the next tick where it has a timeline.
      64           2 :       if (!timeline) {
      65           0 :         iter.Remove();
      66           0 :         continue;
      67             :       }
      68             : 
      69             :       // When the timeline's refresh driver is under test control, its values
      70             :       // have no correspondance to wallclock times so we shouldn't try to
      71             :       // convert aReadyTime (which is a wallclock time) to a timeline value.
      72             :       // Instead, the animation will be started/paused when the refresh driver
      73             :       // is next advanced since this will trigger a call to
      74             :       // TriggerPendingAnimationsNow.
      75           2 :       if (!timeline->TracksWallclockTime()) {
      76           0 :         continue;
      77             :       }
      78             : 
      79           4 :       Nullable<TimeDuration> readyTime = timeline->ToTimelineTime(aReadyTime);
      80           2 :       animation->TriggerOnNextTick(readyTime);
      81             : 
      82           2 :       iter.Remove();
      83             :     }
      84          72 :   };
      85             : 
      86          24 :   triggerAnimationsAtReadyTime(mPlayPendingSet);
      87          24 :   triggerAnimationsAtReadyTime(mPausePendingSet);
      88             : 
      89          48 :   mHasPlayPendingGeometricAnimations = mPlayPendingSet.Count()
      90          24 :                                        ? CheckState::Indeterminate
      91             :                                        : CheckState::Absent;
      92          24 : }
      93             : 
      94             : void
      95           0 : PendingAnimationTracker::TriggerPendingAnimationsNow()
      96             : {
      97           0 :   auto triggerAndClearAnimations = [](AnimationSet& aAnimationSet) {
      98           0 :     for (auto iter = aAnimationSet.Iter(); !iter.Done(); iter.Next()) {
      99           0 :       iter.Get()->GetKey()->TriggerNow();
     100             :     }
     101           0 :     aAnimationSet.Clear();
     102           0 :   };
     103             : 
     104           0 :   triggerAndClearAnimations(mPlayPendingSet);
     105           0 :   triggerAndClearAnimations(mPausePendingSet);
     106             : 
     107           0 :   mHasPlayPendingGeometricAnimations = CheckState::Absent;
     108           0 : }
     109             : 
     110             : void
     111           0 : PendingAnimationTracker::MarkAnimationsThatMightNeedSynchronization()
     112             : {
     113             :   // We only ever set mHasPlayPendingGeometricAnimations to 'present' in
     114             :   // HasPlayPendingGeometricAnimations(). So, if it is 'present' already,
     115             :   // (i.e. before calling HasPlayPendingGeometricAnimations()) we can assume
     116             :   // that this method has already been called for the current set of
     117             :   // play-pending animations and it is not necessary to run again.
     118             :   //
     119             :   // We can't make the same assumption about 'absent', but if this method
     120             :   // was already called and the result was 'absent', then this method is
     121             :   // a no-op anyway so it's ok to run again.
     122             :   //
     123             :   // Note that *without* this optimization, starting animations would become
     124             :   // O(n^2) in that case where each animation is on a different element and
     125             :   // contains a compositor-animatable property since we would end up iterating
     126             :   // over all animations in the play-pending set for each target element.
     127           0 :   if (mHasPlayPendingGeometricAnimations == CheckState::Present) {
     128           0 :     return;
     129             :   }
     130             : 
     131           0 :   if (!HasPlayPendingGeometricAnimations()) {
     132           0 :     return;
     133             :   }
     134             : 
     135           0 :   for (auto iter = mPlayPendingSet.Iter(); !iter.Done(); iter.Next()) {
     136           0 :     iter.Get()->GetKey()->NotifyGeometricAnimationsStartingThisFrame();
     137             :   }
     138             : }
     139             : 
     140             : bool
     141           0 : PendingAnimationTracker::HasPlayPendingGeometricAnimations()
     142             : {
     143           0 :   if (mHasPlayPendingGeometricAnimations != CheckState::Indeterminate) {
     144           0 :     return mHasPlayPendingGeometricAnimations == CheckState::Present;
     145             :   }
     146             : 
     147           0 :   mHasPlayPendingGeometricAnimations = CheckState::Absent;
     148           0 :   for (auto iter = mPlayPendingSet.ConstIter(); !iter.Done(); iter.Next()) {
     149           0 :     auto animation = iter.Get()->GetKey();
     150           0 :     if (animation->GetEffect() && animation->GetEffect()->AffectsGeometry()) {
     151           0 :       mHasPlayPendingGeometricAnimations = CheckState::Present;
     152           0 :       break;
     153             :     }
     154             :   }
     155             : 
     156           0 :   return mHasPlayPendingGeometricAnimations == CheckState::Present;
     157             : }
     158             : 
     159             : void
     160           2 : PendingAnimationTracker::EnsurePaintIsScheduled()
     161             : {
     162           2 :   if (!mDocument) {
     163           0 :     return;
     164             :   }
     165             : 
     166           2 :   nsIPresShell* presShell = mDocument->GetShell();
     167           2 :   if (!presShell) {
     168           0 :     return;
     169             :   }
     170             : 
     171           2 :   nsIFrame* rootFrame = presShell->GetRootFrame();
     172           2 :   if (!rootFrame) {
     173           0 :     return;
     174             :   }
     175             : 
     176           2 :   rootFrame->SchedulePaint();
     177             : }
     178             : 
     179             : } // namespace mozilla

Generated by: LCOV version 1.13