LCOV - code coverage report
Current view: top level - layout/style - AnimationCommon.h (source / functions) Hit Total Coverage
Test: output.info Lines: 68 98 69.4 %
Date: 2017-07-14 16:53:18 Functions: 29 45 64.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #ifndef mozilla_css_AnimationCommon_h
       7             : #define mozilla_css_AnimationCommon_h
       8             : 
       9             : #include <algorithm> // For <std::stable_sort>
      10             : #include "mozilla/AnimationCollection.h"
      11             : #include "mozilla/AnimationComparator.h"
      12             : #include "mozilla/EventDispatcher.h"
      13             : #include "mozilla/LinkedList.h"
      14             : #include "mozilla/MemoryReporting.h"
      15             : #include "mozilla/dom/Animation.h"
      16             : #include "mozilla/AnimationTarget.h"
      17             : #include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
      18             : #include "mozilla/Assertions.h"
      19             : #include "mozilla/TimingParams.h"
      20             : #include "nsContentUtils.h"
      21             : #include "nsCSSPseudoElements.h"
      22             : #include "nsCycleCollectionParticipant.h"
      23             : 
      24             : class nsIFrame;
      25             : class nsPresContext;
      26             : 
      27             : namespace mozilla {
      28             : enum class CSSPseudoElementType : uint8_t;
      29             : 
      30             : namespace dom {
      31             : class Element;
      32             : }
      33             : 
      34             : template <class AnimationType>
      35             : class CommonAnimationManager {
      36             : public:
      37          56 :   explicit CommonAnimationManager(nsPresContext *aPresContext)
      38          56 :     : mPresContext(aPresContext)
      39             :   {
      40          56 :   }
      41             : 
      42             :   // NOTE:  This can return null after Disconnect().
      43             :   nsPresContext* PresContext() const { return mPresContext; }
      44             : 
      45             :   /**
      46             :    * Notify the manager that the pres context is going away.
      47             :    */
      48           8 :   void Disconnect()
      49             :   {
      50             :     // Content nodes might outlive the transition or animation manager.
      51           8 :     RemoveAllElementCollections();
      52             : 
      53           8 :     mPresContext = nullptr;
      54           8 :   }
      55             : 
      56             :   /**
      57             :    * Stop animations on the element. This method takes the real element
      58             :    * rather than the element for the generated content for animations on
      59             :    * ::before and ::after.
      60             :    */
      61        1205 :   void StopAnimationsForElement(dom::Element* aElement,
      62             :                                 CSSPseudoElementType aPseudoType)
      63             :   {
      64        1205 :     MOZ_ASSERT(aElement);
      65             :     AnimationCollection<AnimationType>* collection =
      66             :       AnimationCollection<AnimationType>::GetAnimationCollection(aElement,
      67        1205 :                                                                  aPseudoType);
      68        1205 :     if (!collection) {
      69        1205 :       return;
      70             :     }
      71             : 
      72           0 :     nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
      73           0 :     collection->Destroy();
      74             :   }
      75             : 
      76             : protected:
      77           6 :   virtual ~CommonAnimationManager()
      78             :   {
      79           6 :     MOZ_ASSERT(!mPresContext, "Disconnect should have been called");
      80          12 :   }
      81             : 
      82           2 :   void AddElementCollection(AnimationCollection<AnimationType>* aCollection)
      83             :   {
      84           2 :     mElementCollections.insertBack(aCollection);
      85           2 :   }
      86           8 :   void RemoveAllElementCollections()
      87             :   {
      88           8 :     while (AnimationCollection<AnimationType>* head =
      89           8 :            mElementCollections.getFirst()) {
      90           0 :       head->Destroy(); // Note: this removes 'head' from mElementCollections.
      91             :     }
      92           8 :   }
      93             : 
      94             :   LinkedList<AnimationCollection<AnimationType>> mElementCollections;
      95             :   nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
      96             : };
      97             : 
      98             : /**
      99             :  * Utility class for referencing the element that created a CSS animation or
     100             :  * transition. It is non-owning (i.e. it uses a raw pointer) since it is only
     101             :  * expected to be set by the owned animation while it actually being managed
     102             :  * by the owning element.
     103             :  *
     104             :  * This class also abstracts the comparison of an element/pseudo-class pair
     105             :  * for the sake of composite ordering since this logic is common to both CSS
     106             :  * animations and transitions.
     107             :  *
     108             :  * (We call this OwningElementRef instead of just OwningElement so that we can
     109             :  * call the getter on CSSAnimation/CSSTransition OwningElement() without
     110             :  * clashing with this object's contructor.)
     111             :  */
     112             : class OwningElementRef final
     113             : {
     114             : public:
     115           2 :   OwningElementRef() = default;
     116             : 
     117             :   explicit OwningElementRef(const NonOwningAnimationTarget& aTarget)
     118             :     : mTarget(aTarget)
     119             :   { }
     120             : 
     121           2 :   OwningElementRef(dom::Element& aElement,
     122             :                    CSSPseudoElementType aPseudoType)
     123           2 :     : mTarget(&aElement, aPseudoType)
     124           2 :   { }
     125             : 
     126           3 :   bool Equals(const OwningElementRef& aOther) const
     127             :   {
     128           3 :     return mTarget == aOther.mTarget;
     129             :   }
     130             : 
     131           3 :   bool LessThan(const OwningElementRef& aOther) const
     132             :   {
     133           3 :     MOZ_ASSERT(mTarget.mElement && aOther.mTarget.mElement,
     134             :                "Elements to compare should not be null");
     135             : 
     136           3 :     if (mTarget.mElement != aOther.mTarget.mElement) {
     137           3 :       return nsContentUtils::PositionIsBefore(mTarget.mElement,
     138           6 :                                               aOther.mTarget.mElement);
     139             :     }
     140             : 
     141           0 :     return mTarget.mPseudoType == CSSPseudoElementType::NotPseudo ||
     142           0 :           (mTarget.mPseudoType == CSSPseudoElementType::before &&
     143           0 :            aOther.mTarget.mPseudoType == CSSPseudoElementType::after);
     144             :   }
     145             : 
     146          54 :   bool IsSet() const { return !!mTarget.mElement; }
     147             : 
     148          24 :   void GetElement(dom::Element*& aElement,
     149             :                   CSSPseudoElementType& aPseudoType) const
     150             :   {
     151          24 :     aElement = mTarget.mElement;
     152          24 :     aPseudoType = mTarget.mPseudoType;
     153          24 :   }
     154             : 
     155             : private:
     156             :   NonOwningAnimationTarget mTarget;
     157             : };
     158             : 
     159             : template <class EventInfo>
     160           6 : class DelayedEventDispatcher
     161             : {
     162             : public:
     163          56 :   DelayedEventDispatcher() : mIsSorted(true) { }
     164             : 
     165           6 :   void QueueEvent(EventInfo&& aEventInfo)
     166             :   {
     167           6 :     mPendingEvents.AppendElement(Forward<EventInfo>(aEventInfo));
     168           6 :     mIsSorted = false;
     169           6 :   }
     170             : 
     171             :   // This is exposed as a separate method so that when we are dispatching
     172             :   // *both* transition events and animation events we can sort both lists
     173             :   // once using the current state of the document before beginning any
     174             :   // dispatch.
     175          87 :   void SortEvents()
     176             :   {
     177          87 :     if (mIsSorted) {
     178          84 :       return;
     179             :     }
     180             : 
     181             :     // FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
     182             :     // fixed.
     183           3 :     std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),
     184             :                      EventInfoLessThan());
     185           3 :     mIsSorted = true;
     186             :   }
     187             : 
     188             :   // Takes a reference to the owning manager's pres context so it can
     189             :   // detect if the pres context is destroyed while dispatching one of
     190             :   // the events.
     191             :   //
     192             :   // This will call SortEvents automatically if it has not already been
     193             :   // called.
     194          84 :   void DispatchEvents(nsPresContext* const & aPresContext)
     195             :   {
     196          84 :     if (!aPresContext || mPendingEvents.IsEmpty()) {
     197          81 :       return;
     198             :     }
     199             : 
     200           3 :     SortEvents();
     201             : 
     202           6 :     EventArray events;
     203           3 :     mPendingEvents.SwapElements(events);
     204             :     // mIsSorted will be set to true by SortEvents above, and we leave it
     205             :     // that way since mPendingEvents is now empty
     206           9 :     for (EventInfo& info : events) {
     207           6 :       EventDispatcher::Dispatch(info.mElement, aPresContext, &info.mEvent);
     208             : 
     209           6 :       if (!aPresContext) {
     210           0 :         break;
     211             :       }
     212             :     }
     213             :   }
     214             : 
     215           8 :   void ClearEventQueue()
     216             :   {
     217           8 :     mPendingEvents.Clear();
     218           8 :     mIsSorted = true;
     219           8 :   }
     220             :   bool HasQueuedEvents() const { return !mPendingEvents.IsEmpty(); }
     221             : 
     222             :   // Methods for supporting cycle-collection
     223           0 :   void Traverse(nsCycleCollectionTraversalCallback* aCallback,
     224             :                 const char* aName)
     225             :   {
     226           0 :     for (EventInfo& info : mPendingEvents) {
     227           0 :       ImplCycleCollectionTraverse(*aCallback, info.mElement, aName);
     228           0 :       ImplCycleCollectionTraverse(*aCallback, info.mAnimation, aName);
     229             :     }
     230           0 :   }
     231           0 :   void Unlink() { ClearEventQueue(); }
     232             : 
     233             : protected:
     234             :   class EventInfoLessThan
     235             :   {
     236             :   public:
     237           3 :     bool operator()(const EventInfo& a, const EventInfo& b) const
     238             :     {
     239           3 :       if (a.mTimeStamp != b.mTimeStamp) {
     240             :         // Null timestamps sort first
     241           0 :         if (a.mTimeStamp.IsNull() || b.mTimeStamp.IsNull()) {
     242           0 :           return a.mTimeStamp.IsNull();
     243             :         } else {
     244           0 :           return a.mTimeStamp < b.mTimeStamp;
     245             :         }
     246             :       }
     247             : 
     248             :       AnimationPtrComparator<RefPtr<dom::Animation>> comparator;
     249           3 :       return comparator.LessThan(a.mAnimation, b.mAnimation);
     250             :     }
     251             :   };
     252             : 
     253             :   typedef nsTArray<EventInfo> EventArray;
     254             :   EventArray mPendingEvents;
     255             :   bool mIsSorted;
     256             : };
     257             : 
     258             : template <class EventInfo>
     259             : inline void
     260           0 : ImplCycleCollectionUnlink(DelayedEventDispatcher<EventInfo>& aField)
     261             : {
     262           0 :   aField.Unlink();
     263           0 : }
     264             : 
     265             : template <class EventInfo>
     266             : inline void
     267           0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
     268             :                             DelayedEventDispatcher<EventInfo>& aField,
     269             :                             const char* aName,
     270             :                             uint32_t aFlags = 0)
     271             : {
     272           0 :   aField.Traverse(&aCallback, aName);
     273           0 : }
     274             : 
     275             : // Return the TransitionPhase or AnimationPhase to use when the animation
     276             : // doesn't have a target effect.
     277             : template <typename PhaseType>
     278           0 : PhaseType GetAnimationPhaseWithoutEffect(const dom::Animation& aAnimation)
     279             : {
     280           0 :   MOZ_ASSERT(!aAnimation.GetEffect(),
     281             :              "Should only be called when we do not have an effect");
     282             : 
     283           0 :   Nullable<TimeDuration> currentTime = aAnimation.GetCurrentTime();
     284           0 :   if (currentTime.IsNull()) {
     285           0 :     return PhaseType::Idle;
     286             :   }
     287             : 
     288             :   // If we don't have a target effect, the duration will be zero so the phase is
     289             :   // 'before' if the current time is less than zero.
     290           0 :   return currentTime.Value() < TimeDuration()
     291           0 :          ? PhaseType::Before
     292           0 :          : PhaseType::After;
     293             : };
     294             : 
     295             : inline TimingParams
     296           2 : TimingParamsFromCSSParams(float aDuration, float aDelay,
     297             :                           float aIterationCount,
     298             :                           dom::PlaybackDirection aDirection,
     299             :                           dom::FillMode aFillMode)
     300             : {
     301           2 :   MOZ_ASSERT(aIterationCount >= 0.0 && !IsNaN(aIterationCount),
     302             :              "aIterations should be nonnegative & finite, as ensured by "
     303             :              "CSSParser");
     304             : 
     305             :   return TimingParams {
     306             :     aDuration,
     307             :     aDelay,
     308             :     aIterationCount,
     309             :     aDirection,
     310             :     aFillMode
     311           2 :   };
     312             : }
     313             : 
     314             : } // namespace mozilla
     315             : 
     316             : #endif /* !defined(mozilla_css_AnimationCommon_h) */

Generated by: LCOV version 1.13