gecko-dev/dom/animation/DocumentTimeline.h

120 строки
3.7 KiB
C
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_DocumentTimeline_h
#define mozilla_dom_DocumentTimeline_h
#include "mozilla/dom/DocumentTimelineBinding.h"
#include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h"
#include "AnimationTimeline.h"
#include "nsIDocument.h"
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
#include "nsRefreshDriver.h"
struct JSContext;
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount().
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
namespace mozilla {
namespace dom {
class DocumentTimeline final
: public AnimationTimeline
, public nsARefreshObserver
, public nsATimerAdjustmentObserver
, public LinkedListElement<DocumentTimeline>
{
public:
DocumentTimeline(nsIDocument* aDocument, const TimeDuration& aOriginTime)
: AnimationTimeline(aDocument->GetParentObject())
, mDocument(aDocument)
, mIsObservingRefreshDriver(false)
, mOriginTime(aOriginTime)
{
if (mDocument) {
mDocument->Timelines().insertBack(this);
}
}
protected:
virtual ~DocumentTimeline()
{
MOZ_ASSERT(!mIsObservingRefreshDriver, "Timeline should have disassociated"
" from the refresh driver before being destroyed");
if (isInList()) {
remove();
}
}
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DocumentTimeline,
AnimationTimeline)
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<DocumentTimeline>
Constructor(const GlobalObject& aGlobal,
const DocumentTimelineOptions& aOptions,
ErrorResult& aRv);
// AnimationTimeline methods
virtual Nullable<TimeDuration> GetCurrentTime() const override;
bool TracksWallclockTime() const override
{
nsRefreshDriver* refreshDriver = GetRefreshDriver();
return !refreshDriver ||
!refreshDriver->IsTestControllingRefreshesEnabled();
}
Nullable<TimeDuration> ToTimelineTime(const TimeStamp& aTimeStamp) const
override;
TimeStamp ToTimeStamp(const TimeDuration& aTimelineTime) const override;
Bug 1195180 part 6 - Lazily remove animations from timelines; r=heycam Now that DocumentTimeline observes the refresh driver we can use regular ticks to remove unnecessary animations. We do this because in a subsequent patch, in order to provide deterministic enumeration order when ticking animations, we will store animations in an array. Removing an arbitrary element from an nsTArray is O(n) since we have to search for the array index first, or O(log n) if we keep the array sorted. If we destroy a subtree containing n animations, the operation effectively becomes O(n^2), or, if we keep the array sorted, O(n log n). By destroying during a tick when we are already iterating over the array, however, we will be able to do this much more efficiently. Whether an animation is newly associated with a timeline, or is disassociated from a timeline, or if it merely has its timing updated, the behavior implemented in this patch is to simply make sure we are observing the refresh driver and deal with the animation on the next tick. It might seem that we could be a lot more clever about this and, for example, if an animation reports NeedsTicks() == false, not start observing the refresh driver. There are various edge cases however that need to be taken into account. For example, if a CSS animation is finished (IsRelevant() == false so that animation will have been removed from the timeline), and paused (NeedsTicks() == false), and we seek it back to the point where it is relevant again, we actually need to observe the refresh driver so that it can dispatch an animationstart event on the next tick. A test case in a subsequent patch tests this specific situation. We could possibly add logic to detect if we need to fire events on the next tick but the complexity does not seem warranted given that even if we unnecessarily start observing the refresh driver, we will stop watching it on the next tick. This patch removes some rather lengthy comments from AnimationTiming::UpdateTiming. This is, in part, because of the behavior described above that makes these comments no longer relevant. Other parts are removed because the Web Animations specification has been updated such that a timeline becoming inactive now pauses the animation[1] so that the issue regarding detecting timelines becoming active/inactive no longer applies since animations attached to an inactive timeline remain "relevant". [1] https://w3c.github.io/web-animations/#responding-to-a-newly-inactive-timeline
2015-09-28 06:38:41 +03:00
void NotifyAnimationUpdated(Animation& aAnimation) override;
void RemoveAnimation(Animation* aAnimation) override;
// nsARefreshObserver methods
void WillRefresh(TimeStamp aTime) override;
// nsATimerAdjustmentObserver methods
void NotifyTimerAdjusted(TimeStamp aTime) override;
void NotifyRefreshDriverCreated(nsRefreshDriver* aDriver);
void NotifyRefreshDriverDestroying(nsRefreshDriver* aDriver);
nsIDocument* GetDocument() const override { return mDocument; }
protected:
TimeStamp GetCurrentTimeStamp() const;
nsRefreshDriver* GetRefreshDriver() const;
void UnregisterFromRefreshDriver();
void MostRecentRefreshTimeUpdated();
void ObserveRefreshDriver(nsRefreshDriver* aDriver);
void DisconnectRefreshDriver(nsRefreshDriver* aDriver);
nsCOMPtr<nsIDocument> mDocument;
// The most recently used refresh driver time. This is used in cases where
// we don't have a refresh driver (e.g. because we are in a display:none
// iframe).
mutable TimeStamp mLastRefreshDriverTime;
bool mIsObservingRefreshDriver;
TimeDuration mOriginTime;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_DocumentTimeline_h