Bug 1890002 - Don't create DOM event for those animation events which don't need to be dispatched, r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D206819
This commit is contained in:
Olli Pettay 2024-04-06 08:04:29 +00:00
parent d068628cec
commit 672dda40c9
4 changed files with 46 additions and 26 deletions

View file

@ -10,7 +10,6 @@
#include "AnimationUtils.h" #include "AnimationUtils.h"
#include "mozAutoDocUpdate.h" #include "mozAutoDocUpdate.h"
#include "mozilla/dom/AnimationBinding.h" #include "mozilla/dom/AnimationBinding.h"
#include "mozilla/dom/AnimationPlaybackEvent.h"
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h" #include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DocumentTimeline.h" #include "mozilla/dom/DocumentTimeline.h"
@ -644,7 +643,8 @@ void Animation::Cancel(PostRestyleMode aPostRestyle) {
} }
ResetFinishedPromise(); ResetFinishedPromise();
QueuePlaybackEvent(u"cancel"_ns, GetTimelineCurrentTimeAsTimeStamp()); QueuePlaybackEvent(nsGkAtoms::oncancel,
GetTimelineCurrentTimeAsTimeStamp());
} }
StickyTimeDuration activeTime = StickyTimeDuration activeTime =
@ -1187,7 +1187,7 @@ void Animation::Remove() {
UpdateEffect(PostRestyleMode::IfNeeded); UpdateEffect(PostRestyleMode::IfNeeded);
PostUpdate(); PostUpdate();
QueuePlaybackEvent(u"remove"_ns, GetTimelineCurrentTimeAsTimeStamp()); QueuePlaybackEvent(nsGkAtoms::onremove, GetTimelineCurrentTimeAsTimeStamp());
} }
bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const { bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const {
@ -1866,10 +1866,11 @@ void Animation::DoFinishNotificationImmediately(MicroTaskRunnable* aAsync) {
MaybeResolveFinishedPromise(); 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) { TimeStamp&& aScheduledEventTime) {
// Use document for timing. // Use document for timing.
// https://drafts.csswg.org/web-animations-1/#document-for-timing // https://drafts.csswg.org/web-animations-1/#document-for-timing
@ -1883,20 +1884,19 @@ void Animation::QueuePlaybackEvent(const nsAString& aName,
return; return;
} }
AnimationPlaybackEventInit init; Nullable<double> currentTime;
if (aName.EqualsLiteral("finish") || aName.EqualsLiteral("remove")) { if (aOnEvent == nsGkAtoms::onfinish || aOnEvent == nsGkAtoms::onremove) {
init.mCurrentTime = GetCurrentTimeAsDouble(); currentTime = GetCurrentTimeAsDouble();
} }
Nullable<double> timelineTime;
if (mTimeline) { if (mTimeline) {
init.mTimelineTime = mTimeline->GetCurrentTimeAsDouble(); timelineTime = mTimeline->GetCurrentTimeAsDouble();
} }
RefPtr<AnimationPlaybackEvent> event = presContext->AnimationEventDispatcher()->QueueEvent(
AnimationPlaybackEvent::Constructor(this, aName, init); AnimationEventInfo(aOnEvent, currentTime, timelineTime,
event->SetTrusted(true); std::move(aScheduledEventTime), this));
presContext->AnimationEventDispatcher()->QueueEvent(AnimationEventInfo(
std::move(event), std::move(aScheduledEventTime), this));
} }
bool Animation::IsRunningOnCompositor() const { bool Animation::IsRunningOnCompositor() const {

View file

@ -26,6 +26,7 @@ struct JSContext;
class nsCSSPropertyIDSet; class nsCSSPropertyIDSet;
class nsIFrame; class nsIFrame;
class nsIGlobalObject; class nsIGlobalObject;
class nsAtom;
namespace mozilla { namespace mozilla {
@ -449,8 +450,7 @@ class Animation : public DOMEventTargetHelper,
void DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag); void DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag);
friend class AsyncFinishNotification; friend class AsyncFinishNotification;
void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr); void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr);
void QueuePlaybackEvent(const nsAString& aName, void QueuePlaybackEvent(nsAtom* aOnEvent, TimeStamp&& aScheduledEventTime);
TimeStamp&& aScheduledEventTime);
/** /**
* Remove this animation from the pending animation tracker and reset * Remove this animation from the pending animation tracker and reset

View file

@ -91,10 +91,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEventDispatcher)
ImplCycleCollectionTraverse( ImplCycleCollectionTraverse(
cb, target->mElement, cb, target->mElement,
"mozilla::AnimationEventDispatcher.mPendingEvents.mTarget"); "mozilla::AnimationEventDispatcher.mPendingEvents.mTarget");
} else {
ImplCycleCollectionTraverse(
cb, info.mData.as<AnimationEventInfo::WebAnimationData>().mEvent,
"mozilla::AnimationEventDispatcher.mPendingEvents.mEvent");
} }
ImplCycleCollectionTraverse( ImplCycleCollectionTraverse(
cb, info.mAnimation, cb, info.mAnimation,

View file

@ -12,6 +12,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/ContentEvents.h" #include "mozilla/ContentEvents.h"
#include "mozilla/EventDispatcher.h" #include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/Variant.h" #include "mozilla/Variant.h"
#include "mozilla/dom/AnimationPlaybackEvent.h" #include "mozilla/dom/AnimationPlaybackEvent.h"
#include "mozilla/dom/KeyframeEffect.h" #include "mozilla/dom/KeyframeEffect.h"
@ -44,7 +45,10 @@ struct AnimationEventInfo {
}; };
struct WebAnimationData { 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>; using Data = Variant<CssAnimationData, CssTransitionData, WebAnimationData>;
@ -100,12 +104,15 @@ struct AnimationEventInfo {
} }
// For web animation events // For web animation events
AnimationEventInfo(RefPtr<dom::AnimationPlaybackEvent>&& aEvent, AnimationEventInfo(nsAtom* aOnEvent,
const dom::Nullable<double>& aCurrentTime,
const dom::Nullable<double>& aTimelineTime,
TimeStamp&& aScheduledEventTimeStamp, TimeStamp&& aScheduledEventTimeStamp,
dom::Animation* aAnimation) dom::Animation* aAnimation)
: mAnimation(aAnimation), : mAnimation(aAnimation),
mScheduledEventTimeStamp(std::move(aScheduledEventTimeStamp)), mScheduledEventTimeStamp(std::move(aScheduledEventTimeStamp)),
mData(WebAnimationData{std::move(aEvent)}) {} mData(WebAnimationData{RefPtr{aOnEvent}, aCurrentTime, aTimelineTime}) {
}
AnimationEventInfo(const AnimationEventInfo& aOther) = delete; AnimationEventInfo(const AnimationEventInfo& aOther) = delete;
AnimationEventInfo& operator=(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) // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch(nsPresContext* aPresContext) { MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch(nsPresContext* aPresContext) {
if (mData.is<WebAnimationData>()) { 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; RefPtr target = mAnimation;
EventDispatcher::DispatchDOMEvent(target, nullptr /* WidgetEvent */, EventDispatcher::DispatchDOMEvent(target, nullptr /* WidgetEvent */,
playbackEvent, aPresContext, event, aPresContext,
nullptr /* nsEventStatus */); nullptr /* nsEventStatus */);
return; return;
} }