From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- dom/animation/AnimationEventDispatcher.cpp | 240 +++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 dom/animation/AnimationEventDispatcher.cpp (limited to 'dom/animation/AnimationEventDispatcher.cpp') diff --git a/dom/animation/AnimationEventDispatcher.cpp b/dom/animation/AnimationEventDispatcher.cpp new file mode 100644 index 0000000000..86884abbe5 --- /dev/null +++ b/dom/animation/AnimationEventDispatcher.cpp @@ -0,0 +1,240 @@ +/* -*- 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/. */ + +#include "mozilla/AnimationEventDispatcher.h" + +#include "mozilla/EventDispatcher.h" +#include "nsPresContext.h" +#include "nsRefreshDriver.h" +#include "nsCSSProps.h" +#include "mozilla/dom/AnimationEffect.h" + +using namespace mozilla; + +namespace geckoprofiler::markers { + +struct CSSAnimationMarker { + static constexpr Span MarkerTypeName() { + return MakeStringSpan("CSSAnimation"); + } + static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter, + const nsCString& aName, + const nsCString& aTarget, + const nsCString& aProperties, + const nsCString& aOnCompositor) { + aWriter.StringProperty("Name", aName); + aWriter.StringProperty("Target", aTarget); + aWriter.StringProperty("properties", aProperties); + aWriter.StringProperty("oncompositor", aOnCompositor); + } + static MarkerSchema MarkerTypeDisplay() { + using MS = MarkerSchema; + MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable}; + schema.AddKeyFormatSearchable("Name", MS::Format::String, + MS::Searchable::Searchable); + schema.AddKeyLabelFormat("properties", "Animated Properties", + MS::Format::String); + schema.AddKeyLabelFormat("oncompositor", "Can Run on Compositor", + MS::Format::String); + schema.AddKeyFormat("Target", MS::Format::String); + schema.SetChartLabel("{marker.data.Name}"); + schema.SetTableLabel( + "{marker.name} - {marker.data.Name}: {marker.data.properties}"); + return schema; + } +}; + +struct CSSTransitionMarker { + static constexpr Span MarkerTypeName() { + return MakeStringSpan("CSSTransition"); + } + static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter, + const nsCString& aTarget, + const nsCString& aProperty, + bool aOnCompositor, bool aCanceled) { + aWriter.StringProperty("Target", aTarget); + aWriter.StringProperty("property", aProperty); + aWriter.BoolProperty("oncompositor", aOnCompositor); + if (aCanceled) { + aWriter.BoolProperty("Canceled", aCanceled); + } + } + static MarkerSchema MarkerTypeDisplay() { + using MS = MarkerSchema; + MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable}; + schema.AddKeyLabelFormat("property", "Animated Property", + MS::Format::String); + schema.AddKeyLabelFormat("oncompositor", "Can Run on Compositor", + MS::Format::String); + schema.AddKeyFormat("Canceled", MS::Format::String); + schema.AddKeyFormat("Target", MS::Format::String); + schema.SetChartLabel("{marker.data.property}"); + schema.SetTableLabel("{marker.name} - {marker.data.property}"); + return schema; + } +}; + +} // namespace geckoprofiler::markers + +namespace mozilla { + +NS_IMPL_CYCLE_COLLECTION_CLASS(AnimationEventDispatcher) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AnimationEventDispatcher) + tmp->ClearEventQueue(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEventDispatcher) + for (auto& info : tmp->mPendingEvents) { + if (OwningAnimationTarget* target = info.GetOwningAnimationTarget()) { + ImplCycleCollectionTraverse( + cb, target->mElement, + "mozilla::AnimationEventDispatcher.mPendingEvents.mTarget"); + } else { + ImplCycleCollectionTraverse( + cb, info.mData.as().mEvent, + "mozilla::AnimationEventDispatcher.mPendingEvents.mEvent"); + } + ImplCycleCollectionTraverse( + cb, info.mAnimation, + "mozilla::AnimationEventDispatcher.mPendingEvents.mAnimation"); + } +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +void AnimationEventDispatcher::Disconnect() { + if (mIsObserving) { + MOZ_ASSERT(mPresContext && mPresContext->RefreshDriver(), + "The pres context and the refresh driver should be still " + "alive if we haven't disassociated from the refresh driver"); + mPresContext->RefreshDriver()->CancelPendingAnimationEvents(this); + mIsObserving = false; + } + mPresContext = nullptr; +} + +void AnimationEventDispatcher::QueueEvent(AnimationEventInfo&& aEvent) { + mPendingEvents.AppendElement(std::move(aEvent)); + mIsSorted = false; + ScheduleDispatch(); +} + +void AnimationEventDispatcher::QueueEvents( + nsTArray&& aEvents) { + mPendingEvents.AppendElements(std::move(aEvents)); + mIsSorted = false; + ScheduleDispatch(); +} + +void AnimationEventDispatcher::ScheduleDispatch() { + MOZ_ASSERT(mPresContext, "The pres context should be valid"); + if (!mIsObserving) { + mPresContext->RefreshDriver()->ScheduleAnimationEventDispatch(this); + mIsObserving = true; + } +} + +void AnimationEventInfo::MaybeAddMarker() const { + if (mData.is()) { + const auto& data = mData.as(); + const EventMessage message = data.mMessage; + if (message != eAnimationCancel && message != eAnimationEnd && + message != eAnimationIteration) { + return; + } + nsAutoCString name; + data.mAnimationName->ToUTF8String(name); + const TimeStamp startTime = [&] { + if (message == eAnimationIteration) { + if (auto* effect = mAnimation->GetEffect()) { + return mScheduledEventTimeStamp - + TimeDuration(effect->GetComputedTiming().mDuration); + } + } + return mScheduledEventTimeStamp - + TimeDuration::FromSeconds(data.mElapsedTime); + }(); + + AnimatedPropertyIDSet propertySet; + nsAutoString target; + if (dom::AnimationEffect* effect = mAnimation->GetEffect()) { + if (dom::KeyframeEffect* keyFrameEffect = effect->AsKeyframeEffect()) { + keyFrameEffect->GetTarget()->Describe(target, true); + for (const AnimationProperty& property : keyFrameEffect->Properties()) { + propertySet.AddProperty(property.mProperty); + } + } + } + nsAutoCString properties; + nsAutoCString oncompositor; + for (const AnimatedPropertyID& property : propertySet) { + if (!properties.IsEmpty()) { + properties.AppendLiteral(", "); + oncompositor.AppendLiteral(", "); + } + nsAutoCString prop; + property.ToString(prop); + properties.Append(prop); + oncompositor.Append( + !property.IsCustom() && + nsCSSProps::PropHasFlags(property.mID, + CSSPropFlags::CanAnimateOnCompositor) + ? "true" + : "false"); + } + PROFILER_MARKER( + message == eAnimationIteration + ? ProfilerString8View("CSS animation iteration") + : ProfilerString8View("CSS animation"), + DOM, + MarkerOptions( + MarkerTiming::Interval(startTime, mScheduledEventTimeStamp), + mAnimation->GetOwner() + ? MarkerInnerWindowId(mAnimation->GetOwner()->WindowID()) + : MarkerInnerWindowId::NoId()), + CSSAnimationMarker, name, NS_ConvertUTF16toUTF8(target), properties, + oncompositor); + return; + } + + if (!mData.is()) { + return; + } + + const auto& data = mData.as(); + const EventMessage message = data.mMessage; + if (message != eTransitionEnd && message != eTransitionCancel) { + return; + } + + nsAutoString target; + if (dom::AnimationEffect* effect = mAnimation->GetEffect()) { + if (dom::KeyframeEffect* keyFrameEffect = effect->AsKeyframeEffect()) { + keyFrameEffect->GetTarget()->Describe(target, true); + } + } + nsAutoCString property; + data.mProperty.ToString(property); + + // FIXME: This doesn't _really_ reflect whether the animation is actually run + // in the compositor. The effect has that information and we should use it + // probably. + const bool onCompositor = + !data.mProperty.IsCustom() && + nsCSSProps::PropHasFlags(data.mProperty.mID, + CSSPropFlags::CanAnimateOnCompositor); + PROFILER_MARKER( + "CSS transition", DOM, + MarkerOptions( + MarkerTiming::Interval( + mScheduledEventTimeStamp - + TimeDuration::FromSeconds(data.mElapsedTime), + mScheduledEventTimeStamp), + mAnimation->GetOwner() + ? MarkerInnerWindowId(mAnimation->GetOwner()->WindowID()) + : MarkerInnerWindowId::NoId()), + CSSTransitionMarker, NS_ConvertUTF16toUTF8(target), property, + onCompositor, message == eTransitionCancel); +} + +} // namespace mozilla -- cgit v1.2.3