gecko-dev/dom/animation/EffectCompositor.h
Boris Chiou 95a2a27769 Bug 1814786 - Part 5: Factor out the conversion between (Element, PseudoStyleType) pair and Element. r=hiro
The conversions between an element (including generated content) and the
pair of element and pseudo style type are used frequently, so perhaps it'd
better to factor them out. This patch only moves functions into
AnimationUtils.

FIXME: I suspect Gecko_UpdateAnimations() should early return for the pseudo
elements which we don't support for animations. However, this may cause
some test failures, so we keep the original implementation for now.

Differential Revision: https://phabricator.services.mozilla.com/D159111
2023-03-07 23:57:55 +00:00

259 lines
11 KiB
C++

/* -*- 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 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