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.h307
1 files changed, 307 insertions, 0 deletions
diff --git a/dom/animation/EffectCompositor.h b/dom/animation/EffectCompositor.h
new file mode 100644
index 000000000..732fbb333
--- /dev/null
+++ b/dom/animation/EffectCompositor.h
@@ -0,0 +1,307 @@
+/* -*- 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/EnumeratedArray.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/OwningNonNull.h"
+#include "mozilla/PseudoElementHashEntry.h"
+#include "mozilla/RefPtr.h"
+#include "nsCSSPropertyID.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsDataHashtable.h"
+#include "nsIStyleRuleProcessor.h"
+#include "nsTArray.h"
+
+class nsCSSPropertyIDSet;
+class nsIFrame;
+class nsIStyleRule;
+class nsPresContext;
+class nsStyleContext;
+
+namespace mozilla {
+
+class EffectSet;
+class RestyleTracker;
+struct AnimationPerformanceWarning;
+struct NonOwningAnimationTarget;
+
+namespace dom {
+class Animation;
+class Element;
+}
+
+class EffectCompositor
+{
+public:
+ explicit EffectCompositor(nsPresContext* aPresContext)
+ : mPresContext(aPresContext)
+ {
+ for (size_t i = 0; i < kCascadeLevelCount; i++) {
+ CascadeLevel cascadeLevel = CascadeLevel(i);
+ mRuleProcessors[cascadeLevel] =
+ new AnimationStyleRuleProcessor(this, cascadeLevel);
+ }
+ }
+
+ 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 {
+ // The animations sheet (CSS animations, script-generated animations,
+ // and CSS transitions that are no longer tied to CSS markup)
+ Animations,
+ // The transitions sheet (CSS transitions that are tied to CSS markup)
+ Transitions
+ };
+ // 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,
+ CSSPseudoElementType 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,
+ CSSPseudoElementType 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();
+
+ // Called when the style context 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(nsStyleContext* aStyleContext,
+ dom::Element* aElement,
+ CSSPseudoElementType aPseudoType);
+
+ // Updates the animation rule stored on the EffectSet for the
+ // specified (pseudo-)element for cascade level |aLevel|.
+ // If the animation rule is not marked as needing an update,
+ // no work is done.
+ // |aStyleContext| is used for UpdateCascadingResults.
+ // |aStyleContext| can be nullptr if style context, which is associated with
+ // the primary frame of the specified (pseudo-)element, is the current style
+ // context.
+ // If we are resolving a new style context, we shoud pass the newly created
+ // style context, otherwise we may use an old style context, it will result
+ // unexpected cascading results.
+ void MaybeUpdateAnimationRule(dom::Element* aElement,
+ CSSPseudoElementType aPseudoType,
+ CascadeLevel aCascadeLevel,
+ nsStyleContext *aStyleContext);
+
+ // We need to pass the newly resolved style context as |aStyleContext| when
+ // we call this function during resolving style context because this function
+ // calls UpdateCascadingResults with a style context if necessary, at the
+ // time, we end up using the previous style context if we don't pass the new
+ // style context.
+ // When we are not resolving style context, |aStyleContext| can be nullptr, we
+ // will use a style context associated with the primary frame of the specified
+ // (pseudo-)element.
+ nsIStyleRule* GetAnimationRule(dom::Element* aElement,
+ CSSPseudoElementType aPseudoType,
+ CascadeLevel aCascadeLevel,
+ nsStyleContext* aStyleContext);
+
+ bool HasPendingStyleUpdates() const;
+ bool HasThrottledStyleUpdates() const;
+
+ // Tell the restyle tracker about all the animated styles that have
+ // pending updates so that it can update the animation rule for these
+ // elements.
+ void AddStyleUpdatesTo(RestyleTracker& aTracker);
+
+ nsIStyleRuleProcessor* RuleProcessor(CascadeLevel aCascadeLevel) const
+ {
+ return mRuleProcessors[aCascadeLevel];
+ }
+
+ static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
+ nsCSSPropertyID aProperty);
+
+ static nsTArray<RefPtr<dom::Animation>>
+ GetAnimationsForCompositor(const nsIFrame* aFrame,
+ nsCSSPropertyID aProperty);
+
+ static void ClearIsRunningOnCompositor(const nsIFrame* aFrame,
+ nsCSSPropertyID aProperty);
+
+ // 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.
+ // |aStyleContext| may be nullptr in which case we will use the
+ // nsStyleContext of the primary frame of the specified (pseudo-)element.
+ //
+ // 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,
+ CSSPseudoElementType aPseudoType,
+ nsStyleContext* aStyleContext);
+
+ // Update the mPropertiesWithImportantRules and
+ // mPropertiesForAnimationsLevel members of the corresponding EffectSet.
+ //
+ // 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.
+ static void
+ UpdateCascadeResults(dom::Element* aElement,
+ CSSPseudoElementType aPseudoType,
+ nsStyleContext* aStyleContext);
+
+ // 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.
+ //
+ // 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 animates
+ // |aProperty|.
+ static void SetPerformanceWarning(
+ const nsIFrame* aFrame,
+ nsCSSPropertyID aProperty,
+ const AnimationPerformanceWarning& aWarning);
+
+private:
+ ~EffectCompositor() = default;
+
+ // Rebuilds the animation rule corresponding to |aCascadeLevel| on the
+ // EffectSet associated with the specified (pseudo-)element.
+ static void ComposeAnimationRule(dom::Element* aElement,
+ CSSPseudoElementType aPseudoType,
+ CascadeLevel aCascadeLevel,
+ TimeStamp aRefreshTime);
+
+ static dom::Element* GetElementToRestyle(dom::Element* aElement,
+ CSSPseudoElementType
+ aPseudoType);
+
+ // 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 in |aStyleContext|.
+ static void
+ GetOverriddenProperties(nsStyleContext* aStyleContext,
+ EffectSet& aEffectSet,
+ nsCSSPropertyIDSet& aPropertiesOverridden);
+
+ static void
+ UpdateCascadeResults(EffectSet& aEffectSet,
+ dom::Element* aElement,
+ CSSPseudoElementType aPseudoType,
+ nsStyleContext* aStyleContext);
+
+ 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),
+ nsDataHashtable<PseudoElementHashEntry, bool>>
+ mElementsToRestyle;
+
+ class AnimationStyleRuleProcessor final : public nsIStyleRuleProcessor
+ {
+ public:
+ AnimationStyleRuleProcessor(EffectCompositor* aCompositor,
+ CascadeLevel aCascadeLevel)
+ : mCompositor(aCompositor)
+ , mCascadeLevel(aCascadeLevel)
+ {
+ MOZ_ASSERT(aCompositor);
+ }
+
+ NS_DECL_ISUPPORTS
+
+ // nsIStyleRuleProcessor (parts)
+ nsRestyleHint HasStateDependentStyle(
+ StateRuleProcessorData* aData) override;
+ nsRestyleHint HasStateDependentStyle(
+ PseudoElementStateRuleProcessorData* aData) override;
+ bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) override;
+ nsRestyleHint HasAttributeDependentStyle(
+ AttributeRuleProcessorData* aData,
+ RestyleHintData& aRestyleHintDataResult) override;
+ bool MediumFeaturesChanged(nsPresContext* aPresContext) override;
+ void RulesMatching(ElementRuleProcessorData* aData) override;
+ void RulesMatching(PseudoElementRuleProcessorData* aData) override;
+ void RulesMatching(AnonBoxRuleProcessorData* aData) override;
+#ifdef MOZ_XUL
+ void RulesMatching(XULTreeRuleProcessorData* aData) override;
+#endif
+ size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)
+ const MOZ_MUST_OVERRIDE override;
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
+ const MOZ_MUST_OVERRIDE override;
+
+ private:
+ ~AnimationStyleRuleProcessor() = default;
+
+ EffectCompositor* mCompositor;
+ CascadeLevel mCascadeLevel;
+ };
+
+ EnumeratedArray<CascadeLevel, CascadeLevel(kCascadeLevelCount),
+ OwningNonNull<AnimationStyleRuleProcessor>>
+ mRuleProcessors;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_EffectCompositor_h