summaryrefslogtreecommitdiffstats
path: root/dom/animation
diff options
context:
space:
mode:
Diffstat (limited to 'dom/animation')
-rw-r--r--dom/animation/Animation.cpp59
-rw-r--r--dom/animation/Animation.h10
-rw-r--r--dom/animation/AnimationEventDispatcher.cpp4
-rw-r--r--dom/animation/AnimationEventDispatcher.h34
-rw-r--r--dom/animation/AnimationTimeline.h3
-rw-r--r--dom/animation/test/chrome.toml4
-rw-r--r--dom/animation/test/mozilla/file_restyles.html16
7 files changed, 66 insertions, 64 deletions
diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp
index 6f0fee007c..fbfd689c9a 100644
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -6,11 +6,11 @@
#include "Animation.h"
+#include "mozilla/Likely.h"
#include "nsIFrame.h"
#include "AnimationUtils.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/dom/AnimationBinding.h"
-#include "mozilla/dom/AnimationPlaybackEvent.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DocumentTimeline.h"
@@ -644,7 +644,8 @@ void Animation::Cancel(PostRestyleMode aPostRestyle) {
}
ResetFinishedPromise();
- QueuePlaybackEvent(u"cancel"_ns, GetTimelineCurrentTimeAsTimeStamp());
+ QueuePlaybackEvent(nsGkAtoms::oncancel,
+ GetTimelineCurrentTimeAsTimeStamp());
}
StickyTimeDuration activeTime =
@@ -926,12 +927,13 @@ void Animation::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
void Animation::Tick(AnimationTimeline::TickState& aTickState) {
if (Pending()) {
- // Finish pending if we can, but make sure we've seen one existing tick, or
- // we've requested to get started via SetPendingReadyTime.
- if (!mPendingReadyTime.IsNull() || mSawTickWhilePending) {
+ if (!mPendingReadyTime.IsNull()) {
TryTriggerNow();
+ } else if (MOZ_LIKELY(mTimeline)) {
+ // Makes sure that we trigger the animation on the next tick but,
+ // importantly, with this tick's timestamp.
+ mPendingReadyTime = mTimeline->GetCurrentTimeAsTimeStamp();
}
- mSawTickWhilePending = true;
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
@@ -1187,7 +1189,7 @@ void Animation::Remove() {
UpdateEffect(PostRestyleMode::IfNeeded);
PostUpdate();
- QueuePlaybackEvent(u"remove"_ns, GetTimelineCurrentTimeAsTimeStamp());
+ QueuePlaybackEvent(nsGkAtoms::onremove, GetTimelineCurrentTimeAsTimeStamp());
}
bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const {
@@ -1351,17 +1353,21 @@ void Animation::NotifyEffectTargetUpdated() {
MaybeScheduleReplacementCheck();
}
-static bool EnsurePaintIsScheduled(Document& aDoc) {
+static TimeStamp EnsurePaintIsScheduled(Document& aDoc) {
PresShell* presShell = aDoc.GetPresShell();
if (!presShell) {
- return false;
+ return {};
}
nsIFrame* rootFrame = presShell->GetRootFrame();
if (!rootFrame) {
- return false;
+ return {};
}
rootFrame->SchedulePaintWithoutInvalidatingObservers();
- return rootFrame->PresContext()->RefreshDriver()->IsInRefresh();
+ auto* rd = rootFrame->PresContext()->RefreshDriver();
+ if (!rd->IsInRefresh()) {
+ return {};
+ }
+ return rd->MostRecentRefresh(/* aEnsureTimerStarted = */ false);
}
// https://drafts.csswg.org/web-animations/#play-an-animation
@@ -1453,7 +1459,6 @@ void Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior) {
mPendingState = PendingState::PlayPending;
mPendingReadyTime = {};
- mSawTickWhilePending = false;
if (Document* doc = GetRenderedDocument()) {
if (HasFiniteTimeline()) {
// Always schedule a task even if we would like to let this animation
@@ -1464,7 +1469,7 @@ void Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior) {
doc->GetOrCreateScrollTimelineAnimationTracker()->AddPending(*this);
}
// Make sure to try to schedule a tick.
- mSawTickWhilePending = EnsurePaintIsScheduled(*doc);
+ mPendingReadyTime = EnsurePaintIsScheduled(*doc);
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
@@ -1515,14 +1520,12 @@ void Animation::Pause(ErrorResult& aRv) {
mPendingState = PendingState::PausePending;
mPendingReadyTime = {};
- mSawTickWhilePending = false;
-
// See the relevant PlayPending code for comments.
if (Document* doc = GetRenderedDocument()) {
if (HasFiniteTimeline()) {
doc->GetOrCreateScrollTimelineAnimationTracker()->AddPending(*this);
}
- mSawTickWhilePending = EnsurePaintIsScheduled(*doc);
+ mPendingReadyTime = EnsurePaintIsScheduled(*doc);
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
@@ -1866,10 +1869,11 @@ void Animation::DoFinishNotificationImmediately(MicroTaskRunnable* aAsync) {
MaybeResolveFinishedPromise();
- QueuePlaybackEvent(u"finish"_ns, AnimationTimeToTimeStamp(EffectEnd()));
+ QueuePlaybackEvent(nsGkAtoms::onfinish,
+ AnimationTimeToTimeStamp(EffectEnd()));
}
-void Animation::QueuePlaybackEvent(const nsAString& aName,
+void Animation::QueuePlaybackEvent(nsAtom* aOnEvent,
TimeStamp&& aScheduledEventTime) {
// Use document for timing.
// https://drafts.csswg.org/web-animations-1/#document-for-timing
@@ -1883,20 +1887,19 @@ void Animation::QueuePlaybackEvent(const nsAString& aName,
return;
}
- AnimationPlaybackEventInit init;
- if (aName.EqualsLiteral("finish") || aName.EqualsLiteral("remove")) {
- init.mCurrentTime = GetCurrentTimeAsDouble();
+ Nullable<double> currentTime;
+ if (aOnEvent == nsGkAtoms::onfinish || aOnEvent == nsGkAtoms::onremove) {
+ currentTime = GetCurrentTimeAsDouble();
}
+
+ Nullable<double> timelineTime;
if (mTimeline) {
- init.mTimelineTime = mTimeline->GetCurrentTimeAsDouble();
+ timelineTime = mTimeline->GetCurrentTimeAsDouble();
}
- RefPtr<AnimationPlaybackEvent> event =
- AnimationPlaybackEvent::Constructor(this, aName, init);
- event->SetTrusted(true);
-
- presContext->AnimationEventDispatcher()->QueueEvent(AnimationEventInfo(
- std::move(event), std::move(aScheduledEventTime), this));
+ presContext->AnimationEventDispatcher()->QueueEvent(
+ AnimationEventInfo(aOnEvent, currentTime, timelineTime,
+ std::move(aScheduledEventTime), this));
}
bool Animation::IsRunningOnCompositor() const {
diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h
index cb0859a4b6..e80370370e 100644
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -26,6 +26,7 @@ struct JSContext;
class nsCSSPropertyIDSet;
class nsIFrame;
class nsIGlobalObject;
+class nsAtom;
namespace mozilla {
@@ -114,6 +115,7 @@ class Animation : public DOMEventTargetHelper,
Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
Nullable<double> GetStartTimeAsDouble() const;
void SetStartTime(const Nullable<TimeDuration>& aNewStartTime);
+ const TimeStamp& GetPendingReadyTime() const { return mPendingReadyTime; }
void SetPendingReadyTime(const TimeStamp& aReadyTime) {
mPendingReadyTime = aReadyTime;
}
@@ -449,8 +451,7 @@ class Animation : public DOMEventTargetHelper,
void DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag);
friend class AsyncFinishNotification;
void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr);
- void QueuePlaybackEvent(const nsAString& aName,
- TimeStamp&& aScheduledEventTime);
+ void QueuePlaybackEvent(nsAtom* aOnEvent, TimeStamp&& aScheduledEventTime);
/**
* Remove this animation from the pending animation tracker and reset
@@ -550,11 +551,6 @@ class Animation : public DOMEventTargetHelper,
bool mFinishedAtLastComposeStyle = false;
bool mWasReplaceableAtLastTick = false;
- // When we create a new pending animation, this tracks whether we've seen at
- // least one refresh driver tick. This is used to guarantee that a whole tick
- // has run before triggering the animation, which guarantees (for most pages)
- // that we've actually painted.
- bool mSawTickWhilePending = false;
bool mHiddenByContentVisibility = false;
diff --git a/dom/animation/AnimationEventDispatcher.cpp b/dom/animation/AnimationEventDispatcher.cpp
index 86884abbe5..0ec5686d8f 100644
--- a/dom/animation/AnimationEventDispatcher.cpp
+++ b/dom/animation/AnimationEventDispatcher.cpp
@@ -91,10 +91,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEventDispatcher)
ImplCycleCollectionTraverse(
cb, target->mElement,
"mozilla::AnimationEventDispatcher.mPendingEvents.mTarget");
- } else {
- ImplCycleCollectionTraverse(
- cb, info.mData.as<AnimationEventInfo::WebAnimationData>().mEvent,
- "mozilla::AnimationEventDispatcher.mPendingEvents.mEvent");
}
ImplCycleCollectionTraverse(
cb, info.mAnimation,
diff --git a/dom/animation/AnimationEventDispatcher.h b/dom/animation/AnimationEventDispatcher.h
index 98d1557901..dc11972f6d 100644
--- a/dom/animation/AnimationEventDispatcher.h
+++ b/dom/animation/AnimationEventDispatcher.h
@@ -12,6 +12,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/EventDispatcher.h"
+#include "mozilla/EventListenerManager.h"
#include "mozilla/Variant.h"
#include "mozilla/dom/AnimationPlaybackEvent.h"
#include "mozilla/dom/KeyframeEffect.h"
@@ -44,7 +45,10 @@ struct AnimationEventInfo {
};
struct WebAnimationData {
- RefPtr<dom::AnimationPlaybackEvent> mEvent;
+ const RefPtr<nsAtom> mOnEvent;
+ const dom::Nullable<double> mCurrentTime;
+ const dom::Nullable<double> mTimelineTime;
+ const TimeStamp mEventEnqueueTimeStamp{TimeStamp::Now()};
};
using Data = Variant<CssAnimationData, CssTransitionData, WebAnimationData>;
@@ -100,12 +104,15 @@ struct AnimationEventInfo {
}
// For web animation events
- AnimationEventInfo(RefPtr<dom::AnimationPlaybackEvent>&& aEvent,
+ AnimationEventInfo(nsAtom* aOnEvent,
+ const dom::Nullable<double>& aCurrentTime,
+ const dom::Nullable<double>& aTimelineTime,
TimeStamp&& aScheduledEventTimeStamp,
dom::Animation* aAnimation)
: mAnimation(aAnimation),
mScheduledEventTimeStamp(std::move(aScheduledEventTimeStamp)),
- mData(WebAnimationData{std::move(aEvent)}) {}
+ mData(WebAnimationData{RefPtr{aOnEvent}, aCurrentTime, aTimelineTime}) {
+ }
AnimationEventInfo(const AnimationEventInfo& aOther) = delete;
AnimationEventInfo& operator=(const AnimationEventInfo& aOther) = delete;
@@ -137,10 +144,27 @@ struct AnimationEventInfo {
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch(nsPresContext* aPresContext) {
if (mData.is<WebAnimationData>()) {
- RefPtr playbackEvent = mData.as<WebAnimationData>().mEvent;
+ const auto& data = mData.as<WebAnimationData>();
+ EventListenerManager* elm = mAnimation->GetExistingListenerManager();
+ if (!elm || !elm->HasListenersFor(data.mOnEvent)) {
+ return;
+ }
+
+ dom::AnimationPlaybackEventInit init;
+ init.mCurrentTime = data.mCurrentTime;
+ init.mTimelineTime = data.mTimelineTime;
+ MOZ_ASSERT(nsDependentAtomString(data.mOnEvent).Find(u"on"_ns) == 0,
+ "mOnEvent atom should start with 'on'!");
+ RefPtr<dom::AnimationPlaybackEvent> event =
+ dom::AnimationPlaybackEvent::Constructor(
+ mAnimation, Substring(nsDependentAtomString(data.mOnEvent), 2),
+ init);
+ event->SetTrusted(true);
+ event->WidgetEventPtr()->AssignEventTime(
+ WidgetEventTime(data.mEventEnqueueTimeStamp));
RefPtr target = mAnimation;
EventDispatcher::DispatchDOMEvent(target, nullptr /* WidgetEvent */,
- playbackEvent, aPresContext,
+ event, aPresContext,
nullptr /* nsEventStatus */);
return;
}
diff --git a/dom/animation/AnimationTimeline.h b/dom/animation/AnimationTimeline.h
index 96fd1650a2..bb782bfb8c 100644
--- a/dom/animation/AnimationTimeline.h
+++ b/dom/animation/AnimationTimeline.h
@@ -23,8 +23,7 @@ class ScrollTimeline;
class AnimationTimeline : public nsISupports, public nsWrapperCache {
public:
- explicit AnimationTimeline(nsIGlobalObject* aWindow,
- RTPCallerType aRTPCallerType);
+ AnimationTimeline(nsIGlobalObject* aWindow, RTPCallerType);
struct TickState {
TickState() = default;
diff --git a/dom/animation/test/chrome.toml b/dom/animation/test/chrome.toml
index fa1d21457c..0783d9bb5a 100644
--- a/dom/animation/test/chrome.toml
+++ b/dom/animation/test/chrome.toml
@@ -5,10 +5,6 @@ prefs = [
"layout.css.basic-shape-rect.enabled=true",
"layout.css.basic-shape-xywh.enabled=true",
"layout.css.individual-transform.enabled=true",
- "layout.css.motion-path-basic-shapes.enabled=true",
- "layout.css.motion-path-coord-box.enabled=true",
- "layout.css.motion-path-offset-position.enabled=true",
- "layout.css.motion-path-ray.enabled=true",
]
support-files = [
"testcommon.js",
diff --git a/dom/animation/test/mozilla/file_restyles.html b/dom/animation/test/mozilla/file_restyles.html
index 0aba35cd0e..88e6329b69 100644
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -975,13 +975,7 @@ waitForAllPaints(() => {
animation.pause();
await animation.ready;
- let restyleCount;
- restyleCount = await observeStyling(1);
- is(restyleCount, 1,
- 'Animations running on the compositor should restyle once after ' +
- 'Animation.pause() was called');
-
- restyleCount = await observeStyling(5);
+ let restyleCount = await observeStyling(5);
is(restyleCount, 0,
'Paused animations running on the compositor should never cause ' +
'restyles');
@@ -997,13 +991,7 @@ waitForAllPaints(() => {
animation.pause();
await animation.ready;
- let restyleCount;
- restyleCount = await observeStyling(1);
- is(restyleCount, 1,
- 'Animations running on the main-thread should restyle once after ' +
- 'Animation.pause() was called');
-
- restyleCount = await observeStyling(5);
+ let restyleCount = await observeStyling(5);
is(restyleCount, 0,
'Paused animations running on the main-thread should never cause ' +
'restyles');