LCOV - code coverage report
Current view: top level - dom/animation - DocumentTimeline.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 75 127 59.1 %
Date: 2017-07-14 16:53:18 Functions: 12 19 63.2 %
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 "DocumentTimeline.h"
       8             : #include "mozilla/dom/DocumentTimelineBinding.h"
       9             : #include "AnimationUtils.h"
      10             : #include "nsContentUtils.h"
      11             : #include "nsDOMMutationObserver.h"
      12             : #include "nsDOMNavigationTiming.h"
      13             : #include "nsIPresShell.h"
      14             : #include "nsPresContext.h"
      15             : #include "nsRefreshDriver.h"
      16             : 
      17             : namespace mozilla {
      18             : namespace dom {
      19             : 
      20             : NS_IMPL_CYCLE_COLLECTION_CLASS(DocumentTimeline)
      21           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocumentTimeline,
      22             :                                                 AnimationTimeline)
      23           0 :   tmp->UnregisterFromRefreshDriver();
      24           0 :   if (tmp->isInList()) {
      25           0 :     tmp->remove();
      26             :   }
      27           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
      28           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      29           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DocumentTimeline,
      30             :                                                   AnimationTimeline)
      31           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
      32           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      33             : 
      34           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DocumentTimeline,
      35             :                                                AnimationTimeline)
      36           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
      37             : 
      38          22 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocumentTimeline)
      39           0 : NS_INTERFACE_MAP_END_INHERITING(AnimationTimeline)
      40             : 
      41          36 : NS_IMPL_ADDREF_INHERITED(DocumentTimeline, AnimationTimeline)
      42          12 : NS_IMPL_RELEASE_INHERITED(DocumentTimeline, AnimationTimeline)
      43             : 
      44             : JSObject*
      45           0 : DocumentTimeline::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
      46             : {
      47           0 :   return DocumentTimelineBinding::Wrap(aCx, this, aGivenProto);
      48             : }
      49             : 
      50             : /* static */ already_AddRefed<DocumentTimeline>
      51           0 : DocumentTimeline::Constructor(const GlobalObject& aGlobal,
      52             :                               const DocumentTimelineOptions& aOptions,
      53             :                               ErrorResult& aRv)
      54             : {
      55           0 :   nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
      56           0 :   if (!doc) {
      57           0 :     aRv.Throw(NS_ERROR_FAILURE);
      58           0 :     return nullptr;
      59             :   }
      60             :   TimeDuration originTime =
      61           0 :     TimeDuration::FromMilliseconds(aOptions.mOriginTime);
      62             : 
      63           0 :   if (originTime == TimeDuration::Forever() ||
      64           0 :       originTime == -TimeDuration::Forever()) {
      65           0 :     aRv.ThrowTypeError<dom::MSG_TIME_VALUE_OUT_OF_RANGE>(
      66           0 :       NS_LITERAL_STRING("Origin time"));
      67           0 :     return nullptr;
      68             :   }
      69           0 :   RefPtr<DocumentTimeline> timeline = new DocumentTimeline(doc, originTime);
      70             : 
      71           0 :   return timeline.forget();
      72             : }
      73             : 
      74             : Nullable<TimeDuration>
      75         116 : DocumentTimeline::GetCurrentTime() const
      76             : {
      77         116 :   return ToTimelineTime(GetCurrentTimeStamp());
      78             : }
      79             : 
      80             : TimeStamp
      81         116 : DocumentTimeline::GetCurrentTimeStamp() const
      82             : {
      83         116 :   nsRefreshDriver* refreshDriver = GetRefreshDriver();
      84             :   TimeStamp refreshTime = refreshDriver
      85             :                           ? refreshDriver->MostRecentRefresh()
      86         116 :                           : TimeStamp();
      87             : 
      88             :   // Always return the same object to benefit from return-value optimization.
      89         116 :   TimeStamp result = !refreshTime.IsNull()
      90         116 :                      ? refreshTime
      91         116 :                      : mLastRefreshDriverTime;
      92             : 
      93             :   // If we don't have a refresh driver and we've never had one use the
      94             :   // timeline's zero time.
      95         116 :   if (result.IsNull()) {
      96           0 :     nsDOMNavigationTiming* timing = mDocument->GetNavigationTiming();
      97           0 :     if (timing) {
      98           0 :       result = timing->GetNavigationStartTimeStamp();
      99             :       // Also, let this time represent the current refresh time. This way
     100             :       // we'll save it as the last refresh time and skip looking up
     101             :       // navigation timing each time.
     102           0 :       refreshTime = result;
     103             :     }
     104             :   }
     105             : 
     106         116 :   if (!refreshTime.IsNull()) {
     107         116 :     mLastRefreshDriverTime = refreshTime;
     108             :   }
     109             : 
     110         116 :   return result;
     111             : }
     112             : 
     113             : Nullable<TimeDuration>
     114         118 : DocumentTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const
     115             : {
     116         118 :   Nullable<TimeDuration> result; // Initializes to null
     117         118 :   if (aTimeStamp.IsNull()) {
     118           0 :     return result;
     119             :   }
     120             : 
     121         118 :   nsDOMNavigationTiming* timing = mDocument->GetNavigationTiming();
     122         118 :   if (MOZ_UNLIKELY(!timing)) {
     123           0 :     return result;
     124             :   }
     125             : 
     126             :   result.SetValue(aTimeStamp
     127         236 :                   - timing->GetNavigationStartTimeStamp()
     128         236 :                   - mOriginTime);
     129         118 :   return result;
     130             : }
     131             : 
     132             : void
     133          32 : DocumentTimeline::NotifyAnimationUpdated(Animation& aAnimation)
     134             : {
     135          32 :   AnimationTimeline::NotifyAnimationUpdated(aAnimation);
     136             : 
     137          32 :   if (!mIsObservingRefreshDriver) {
     138           1 :     nsRefreshDriver* refreshDriver = GetRefreshDriver();
     139           1 :     if (refreshDriver) {
     140           1 :       MOZ_ASSERT(isInList(),
     141             :                 "We should not register with the refresh driver if we are not"
     142             :                 " in the document's list of timelines");
     143           1 :       refreshDriver->AddRefreshObserver(this, FlushType::Style);
     144           1 :       mIsObservingRefreshDriver = true;
     145             :     }
     146             :   }
     147          32 : }
     148             : 
     149             : void
     150          12 : DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime)
     151             : {
     152          12 :   MOZ_ASSERT(mIsObservingRefreshDriver);
     153          12 :   MOZ_ASSERT(GetRefreshDriver(),
     154             :              "Should be able to reach refresh driver from within WillRefresh");
     155             : 
     156          12 :   bool needsTicks = false;
     157          24 :   nsTArray<Animation*> animationsToRemove(mAnimations.Count());
     158             : 
     159          24 :   nsAutoAnimationMutationBatch mb(mDocument);
     160             : 
     161          36 :   for (Animation* animation = mAnimationOrder.getFirst(); animation;
     162          24 :        animation = animation->getNext()) {
     163             :     // Skip any animations that are longer need associated with this timeline.
     164          24 :     if (animation->GetTimeline() != this) {
     165             :       // If animation has some other timeline, it better not be also in the
     166             :       // animation list of this timeline object!
     167           0 :       MOZ_ASSERT(!animation->GetTimeline());
     168           0 :       animationsToRemove.AppendElement(animation);
     169           0 :       continue;
     170             :     }
     171             : 
     172          24 :     needsTicks |= animation->NeedsTicks();
     173             :     // Even if |animation| doesn't need future ticks, we should still
     174             :     // Tick it this time around since it might just need a one-off tick in
     175             :     // order to dispatch events.
     176          24 :     animation->Tick();
     177             : 
     178          24 :     if (!animation->IsRelevant() && !animation->NeedsTicks()) {
     179           2 :       animationsToRemove.AppendElement(animation);
     180             :     }
     181             :   }
     182             : 
     183          14 :   for (Animation* animation : animationsToRemove) {
     184           2 :     RemoveAnimation(animation);
     185             :   }
     186             : 
     187          12 :   if (!needsTicks) {
     188             :     // We already assert that GetRefreshDriver() is non-null at the beginning
     189             :     // of this function but we check it again here to be sure that ticking
     190             :     // animations does not have any side effects that cause us to lose the
     191             :     // connection with the refresh driver, such as triggering the destruction
     192             :     // of mDocument's PresShell.
     193           1 :     MOZ_ASSERT(GetRefreshDriver(),
     194             :                "Refresh driver should still be valid at end of WillRefresh");
     195           1 :     UnregisterFromRefreshDriver();
     196             :   }
     197          12 : }
     198             : 
     199             : void
     200           0 : DocumentTimeline::NotifyRefreshDriverCreated(nsRefreshDriver* aDriver)
     201             : {
     202           0 :   MOZ_ASSERT(!mIsObservingRefreshDriver,
     203             :              "Timeline should not be observing the refresh driver before"
     204             :              " it is created");
     205             : 
     206           0 :   if (!mAnimationOrder.isEmpty()) {
     207           0 :     MOZ_ASSERT(isInList(),
     208             :                "We should not register with the refresh driver if we are not"
     209             :                " in the document's list of timelines");
     210           0 :     aDriver->AddRefreshObserver(this, FlushType::Style);
     211           0 :     mIsObservingRefreshDriver = true;
     212             :   }
     213           0 : }
     214             : 
     215             : void
     216           0 : DocumentTimeline::NotifyRefreshDriverDestroying(nsRefreshDriver* aDriver)
     217             : {
     218           0 :   if (!mIsObservingRefreshDriver) {
     219           0 :     return;
     220             :   }
     221             : 
     222           0 :   aDriver->RemoveRefreshObserver(this, FlushType::Style);
     223           0 :   mIsObservingRefreshDriver = false;
     224             : }
     225             : 
     226             : void
     227           2 : DocumentTimeline::RemoveAnimation(Animation* aAnimation)
     228             : {
     229           2 :   AnimationTimeline::RemoveAnimation(aAnimation);
     230             : 
     231           2 :   if (mIsObservingRefreshDriver && mAnimations.IsEmpty()) {
     232           1 :     UnregisterFromRefreshDriver();
     233             :   }
     234           2 : }
     235             : 
     236             : TimeStamp
     237          18 : DocumentTimeline::ToTimeStamp(const TimeDuration& aTimeDuration) const
     238             : {
     239          18 :   TimeStamp result;
     240          36 :   RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
     241          18 :   if (MOZ_UNLIKELY(!timing)) {
     242           0 :     return result;
     243             :   }
     244             : 
     245             :   result =
     246          18 :     timing->GetNavigationStartTimeStamp() + (aTimeDuration + mOriginTime);
     247          18 :   return result;
     248             : }
     249             : 
     250             : nsRefreshDriver*
     251         133 : DocumentTimeline::GetRefreshDriver() const
     252             : {
     253         133 :   nsIPresShell* presShell = mDocument->GetShell();
     254         133 :   if (MOZ_UNLIKELY(!presShell)) {
     255           0 :     return nullptr;
     256             :   }
     257             : 
     258         133 :   nsPresContext* presContext = presShell->GetPresContext();
     259         133 :   if (MOZ_UNLIKELY(!presContext)) {
     260           0 :     return nullptr;
     261             :   }
     262             : 
     263         133 :   return presContext->RefreshDriver();
     264             : }
     265             : 
     266             : void
     267           2 : DocumentTimeline::UnregisterFromRefreshDriver()
     268             : {
     269           2 :   if (!mIsObservingRefreshDriver) {
     270           1 :     return;
     271             :   }
     272             : 
     273           1 :   nsRefreshDriver* refreshDriver = GetRefreshDriver();
     274           1 :   if (!refreshDriver) {
     275           0 :     return;
     276             :   }
     277             : 
     278           1 :   refreshDriver->RemoveRefreshObserver(this, FlushType::Style);
     279           1 :   mIsObservingRefreshDriver = false;
     280             : }
     281             : 
     282             : } // namespace dom
     283             : } // namespace mozilla

Generated by: LCOV version 1.13