summaryrefslogtreecommitdiffstats
path: root/dom/animation/EffectCompositor.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/animation/EffectCompositor.h')
-rw-r--r--dom/animation/EffectCompositor.h267
1 files changed, 267 insertions, 0 deletions
diff --git a/dom/animation/EffectCompositor.h b/dom/animation/EffectCompositor.h
new file mode 100644
index 0000000000..622fb2ec1b
--- /dev/null
+++ b/dom/animation/EffectCompositor.h
@@ -0,0 +1,267 @@
+/* -*- 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_EffectCompositor_h
+#define mozilla_EffectCompositor_h
+
+#include "mozilla/AnimationPerformanceWarning.h"
+#include "mozilla/AnimationTarget.h"
+#include "mozilla/EnumeratedArray.h"
+#include "mozilla/HashTable.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/OwningNonNull.h"
+#include "mozilla/PseudoElementHashEntry.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/ServoTypes.h"
+#include "nsCSSPropertyID.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsTHashMap.h"
+#include "nsTArray.h"
+
+class nsCSSPropertyIDSet;
+class nsAtom;
+class nsIFrame;
+class nsPresContext;
+enum class DisplayItemType : uint8_t;
+struct RawServoAnimationValueMap;
+
+namespace mozilla {
+
+class ComputedStyle;
+class EffectSet;
+class RestyleTracker;
+class StyleAnimationValue;
+struct AnimationProperty;
+struct NonOwningAnimationTarget;
+
+namespace dom {
+class Animation;
+class Element;
+class KeyframeEffect;
+} // namespace dom
+
+class EffectCompositor {
+ public:
+ explicit EffectCompositor(nsPresContext* aPresContext)
+ : mPresContext(aPresContext) {}
+
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EffectCompositor)
+ NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EffectCompositor)
+
+ void Disconnect() { mPresContext = nullptr; }
+
+ // Animations can be applied at two different levels in the CSS cascade:
+ enum class CascadeLevel : uint32_t {
+ // The animations sheet (CSS animations, script-generated animations,
+ // and CSS transitions that are no longer tied to CSS markup)
+ Animations = 0,
+ // The transitions sheet (CSS transitions that are tied to CSS markup)
+ Transitions = 1
+ };
+ // We don't define this as part of CascadeLevel as then we'd have to add
+ // explicit checks for the Count enum value everywhere CascadeLevel is used.
+ static const size_t kCascadeLevelCount =
+ static_cast<size_t>(CascadeLevel::Transitions) + 1;
+
+ // NOTE: This can return null after Disconnect().
+ nsPresContext* PresContext() const { return mPresContext; }
+
+ enum class RestyleType {
+ // Animation style has changed but the compositor is applying the same
+ // change so we might be able to defer updating the main thread until it
+ // becomes necessary.
+ Throttled,
+ // Animation style has changed and needs to be updated on the main thread.
+ Standard,
+ // Animation style has changed and needs to be updated on the main thread
+ // as well as forcing animations on layers to be updated.
+ // This is needed in cases such as when an animation becomes paused or has
+ // its playback rate changed. In such cases, although the computed style
+ // and refresh driver time might not change, we still need to ensure the
+ // corresponding animations on layers are updated to reflect the new
+ // configuration of the animation.
+ Layer
+ };
+
+ // Notifies the compositor that the animation rule for the specified
+ // (pseudo-)element at the specified cascade level needs to be updated.
+ // The specified steps taken to update the animation rule depend on
+ // |aRestyleType| whose values are described above.
+ void RequestRestyle(dom::Element* aElement, PseudoStyleType aPseudoType,
+ RestyleType aRestyleType, CascadeLevel aCascadeLevel);
+
+ // Schedule an animation restyle. This is called automatically by
+ // RequestRestyle when necessary. However, it is exposed here since we also
+ // need to perform this step when triggering transitions *without* also
+ // invalidating the animation style rule (which RequestRestyle would do).
+ void PostRestyleForAnimation(dom::Element* aElement,
+ PseudoStyleType aPseudoType,
+ CascadeLevel aCascadeLevel);
+
+ // Posts an animation restyle for any elements whose animation style rule
+ // is out of date but for which an animation restyle has not yet been
+ // posted because updates on the main thread are throttled.
+ void PostRestyleForThrottledAnimations();
+
+ // Clear all pending restyle requests for the given (pseudo-) element (and its
+ // ::before, ::after and ::marker elements if the given element is not
+ // pseudo).
+ void ClearRestyleRequestsFor(dom::Element* aElement);
+
+ // Called when computed style on the specified (pseudo-) element might
+ // have changed so that any context-sensitive values stored within
+ // animation effects (e.g. em-based endpoints used in keyframe effects)
+ // can be re-resolved to computed values.
+ void UpdateEffectProperties(const ComputedStyle* aStyle,
+ dom::Element* aElement,
+ PseudoStyleType aPseudoType);
+
+ // Get the animation rule for the appropriate level of the cascade for
+ // a (pseudo-)element. Called from the Servo side.
+ //
+ // The animation rule is stored in |RawServoAnimationValueMap|.
+ // We need to be careful while doing any modification because it may cause
+ // some thread-safe issues.
+ bool GetServoAnimationRule(const dom::Element* aElement,
+ PseudoStyleType aPseudoType,
+ CascadeLevel aCascadeLevel,
+ RawServoAnimationValueMap* aAnimationValues);
+
+ // A variant on GetServoAnimationRule that composes all the effects for an
+ // element up to and including |aEffect|.
+ //
+ // Note that |aEffect| might not be in the EffectSet since we can use this for
+ // committing the computed style of a removed Animation.
+ bool ComposeServoAnimationRuleForEffect(
+ dom::KeyframeEffect& aEffect, CascadeLevel aCascadeLevel,
+ RawServoAnimationValueMap* aAnimationValues);
+
+ bool HasPendingStyleUpdates() const;
+
+ static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
+ DisplayItemType aType);
+
+ static nsTArray<RefPtr<dom::Animation>> GetAnimationsForCompositor(
+ const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet);
+
+ static void ClearIsRunningOnCompositor(const nsIFrame* aFrame,
+ DisplayItemType aType);
+
+ // Update animation cascade results for the specified (pseudo-)element
+ // but only if we have marked the cascade as needing an update due a
+ // the change in the set of effects or a change in one of the effects'
+ // "in effect" state.
+ //
+ // This method does NOT detect if other styles that apply above the
+ // animation level of the cascade have changed.
+ static void MaybeUpdateCascadeResults(dom::Element* aElement,
+ PseudoStyleType aPseudoType);
+
+ // Update the mPropertiesWithImportantRules and
+ // mPropertiesForAnimationsLevel members of the given EffectSet, and also
+ // request any restyles required by changes to the cascade result.
+ //
+ // NOTE: This can be expensive so we should only call it if styles that apply
+ // above the animation level of the cascade might have changed. For all
+ // other cases we should call MaybeUpdateCascadeResults.
+ //
+ // This is typically reserved for internal callers but is public here since
+ // when we detect changes to the cascade on the Servo side we can't call
+ // MarkCascadeNeedsUpdate during the traversal so instead we call this as part
+ // of a follow-up sequential task.
+ static void UpdateCascadeResults(EffectSet& aEffectSet,
+ dom::Element* aElement,
+ PseudoStyleType aPseudoType);
+
+ // Helper to fetch the corresponding element and pseudo-type from a frame.
+ //
+ // For frames corresponding to pseudo-elements, the returned element is the
+ // element on which we store the animations (i.e. the EffectSet and/or
+ // AnimationCollection), *not* the generated content.
+ //
+ // For display:table content, which maintains a distinction between primary
+ // frame (table wrapper frame) and style frame (inner table frame), animations
+ // are stored on the content associated with the _style_ frame even though
+ // some (particularly transform-like animations) may be applied to the
+ // _primary_ frame. As a result, callers will typically want to pass the style
+ // frame to this function.
+ //
+ // Returns an empty result when a suitable element cannot be found including
+ // when the frame represents a pseudo-element on which we do not support
+ // animations.
+ static Maybe<NonOwningAnimationTarget> GetAnimationElementAndPseudoForFrame(
+ const nsIFrame* aFrame);
+
+ // Associates a performance warning with effects on |aFrame| that animate
+ // properties in |aPropertySet|.
+ static void SetPerformanceWarning(
+ const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
+ const AnimationPerformanceWarning& aWarning);
+
+ // Do a bunch of stuff that we should avoid doing during the parallel
+ // traversal (e.g. changing member variables) for all elements that we expect
+ // to restyle on the next traversal.
+ //
+ // Returns true if there are elements needing a restyle for animation.
+ bool PreTraverse(ServoTraversalFlags aFlags);
+
+ // Similar to the above but for all elements in the subtree rooted
+ // at aElement.
+ bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
+
+ // Record a (pseudo-)element that may have animations that can be removed.
+ void NoteElementForReducing(const NonOwningAnimationTarget& aTarget);
+
+ bool NeedsReducing() const { return !mElementsToReduce.empty(); }
+ void ReduceAnimations();
+
+ // Returns the target element for restyling.
+ //
+ // If |aPseudoType| is ::after, ::before or ::marker, returns the generated
+ // content element of which |aElement| is the parent. If |aPseudoType| is any
+ // other pseudo type (other than PseudoStyleType::NotPseudo) returns nullptr.
+ // Otherwise, returns |aElement|.
+ static dom::Element* GetElementToRestyle(dom::Element* aElement,
+ PseudoStyleType aPseudoType);
+
+ // Returns true if any type of compositor animations on |aFrame| allow
+ // runnning on the compositor.
+ // Sets the reason in |aWarning| if the result is false.
+ static bool AllowCompositorAnimationsOnFrame(
+ const nsIFrame* aFrame,
+ AnimationPerformanceWarning::Type& aWarning /* out */);
+
+ private:
+ ~EffectCompositor() = default;
+
+ // Get the properties in |aEffectSet| that we are able to animate on the
+ // compositor but which are also specified at a higher level in the cascade
+ // than the animations level.
+ static nsCSSPropertyIDSet GetOverriddenProperties(
+ EffectSet& aEffectSet, dom::Element* aElement,
+ PseudoStyleType aPseudoType);
+
+ static nsPresContext* GetPresContext(dom::Element* aElement);
+
+ nsPresContext* mPresContext;
+
+ // Elements with a pending animation restyle. The associated bool value is
+ // true if a pending animation restyle has also been dispatched. For
+ // animations that can be throttled, we will add an entry to the hashtable to
+ // indicate that the style rule on the element is out of date but without
+ // posting a restyle to update it.
+ EnumeratedArray<CascadeLevel, CascadeLevel(kCascadeLevelCount),
+ nsTHashMap<PseudoElementHashEntry, bool>>
+ mElementsToRestyle;
+
+ bool mIsInPreTraverse = false;
+
+ HashSet<OwningAnimationTarget> mElementsToReduce;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_EffectCompositor_h