diff options
Diffstat (limited to 'dom/animation')
-rw-r--r-- | dom/animation/Animation.cpp | 59 | ||||
-rw-r--r-- | dom/animation/Animation.h | 10 | ||||
-rw-r--r-- | dom/animation/AnimationEventDispatcher.cpp | 4 | ||||
-rw-r--r-- | dom/animation/AnimationEventDispatcher.h | 34 | ||||
-rw-r--r-- | dom/animation/AnimationTimeline.h | 3 | ||||
-rw-r--r-- | dom/animation/test/chrome.toml | 4 | ||||
-rw-r--r-- | dom/animation/test/mozilla/file_restyles.html | 16 |
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'); |