tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EffectCompositor.h (11112B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_EffectCompositor_h
      8 #define mozilla_EffectCompositor_h
      9 
     10 #include "NonCustomCSSPropertyId.h"
     11 #include "mozilla/AnimationPerformanceWarning.h"
     12 #include "mozilla/AnimationTarget.h"
     13 #include "mozilla/EnumeratedArray.h"
     14 #include "mozilla/HashTable.h"
     15 #include "mozilla/Maybe.h"
     16 #include "mozilla/OwningNonNull.h"
     17 #include "mozilla/PseudoElementHashEntry.h"
     18 #include "mozilla/RefPtr.h"
     19 #include "mozilla/ServoTypes.h"
     20 #include "mozilla/dom/EndpointBehavior.h"
     21 #include "nsCycleCollectionParticipant.h"
     22 #include "nsTArray.h"
     23 #include "nsTHashMap.h"
     24 
     25 class nsCSSPropertyIDSet;
     26 class nsAtom;
     27 class nsIFrame;
     28 class nsPresContext;
     29 enum class DisplayItemType : uint8_t;
     30 
     31 namespace mozilla {
     32 
     33 class ComputedStyle;
     34 class EffectSet;
     35 class RestyleTracker;
     36 struct StyleAnimationValue;
     37 struct StyleAnimationValueMap;
     38 struct AnimationProperty;
     39 struct NonOwningAnimationTarget;
     40 
     41 namespace dom {
     42 class Animation;
     43 class Element;
     44 class KeyframeEffect;
     45 }  // namespace dom
     46 
     47 class EffectCompositor {
     48 public:
     49  explicit EffectCompositor(nsPresContext* aPresContext)
     50      : mPresContext(aPresContext) {}
     51 
     52  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EffectCompositor)
     53  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EffectCompositor)
     54 
     55  void Disconnect() { mPresContext = nullptr; }
     56 
     57  // Animations can be applied at two different levels in the CSS cascade:
     58  enum class CascadeLevel : uint32_t {
     59    // The animations sheet (CSS animations, script-generated animations,
     60    // and CSS transitions that are no longer tied to CSS markup)
     61    Animations = 0,
     62    // The transitions sheet (CSS transitions that are tied to CSS markup)
     63    Transitions = 1
     64  };
     65  // We don't define this as part of CascadeLevel as then we'd have to add
     66  // explicit checks for the Count enum value everywhere CascadeLevel is used.
     67  static const size_t kCascadeLevelCount =
     68      static_cast<size_t>(CascadeLevel::Transitions) + 1;
     69 
     70  // NOTE: This can return null after Disconnect().
     71  nsPresContext* PresContext() const { return mPresContext; }
     72 
     73  enum class RestyleType {
     74    // Animation style has changed but the compositor is applying the same
     75    // change so we might be able to defer updating the main thread until it
     76    // becomes necessary.
     77    Throttled,
     78    // Animation style has changed and needs to be updated on the main thread.
     79    Standard,
     80    // Animation style has changed and needs to be updated on the main thread
     81    // as well as forcing animations on layers to be updated.
     82    // This is needed in cases such as when an animation becomes paused or has
     83    // its playback rate changed. In such cases, although the computed style
     84    // and refresh driver time might not change, we still need to ensure the
     85    // corresponding animations on layers are updated to reflect the new
     86    // configuration of the animation.
     87    Layer
     88  };
     89 
     90  // Notifies the compositor that the animation rule for the specified
     91  // (pseudo-)element at the specified cascade level needs to be updated.
     92  // The specified steps taken to update the animation rule depend on
     93  // |aRestyleType| whose values are described above.
     94  void RequestRestyle(dom::Element* aElement,
     95                      const PseudoStyleRequest& aPseudoRequest,
     96                      RestyleType aRestyleType, CascadeLevel aCascadeLevel);
     97 
     98  // Schedule an animation restyle. This is called automatically by
     99  // RequestRestyle when necessary. However, it is exposed here since we also
    100  // need to perform this step when triggering transitions *without* also
    101  // invalidating the animation style rule (which RequestRestyle would do).
    102  void PostRestyleForAnimation(dom::Element* aElement,
    103                               const PseudoStyleRequest& aPseudoRequest,
    104                               CascadeLevel aCascadeLevel);
    105 
    106  // Posts an animation restyle for any elements whose animation style rule
    107  // is out of date but for which an animation restyle has not yet been
    108  // posted because updates on the main thread are throttled.
    109  void PostRestyleForThrottledAnimations();
    110 
    111  // Called when computed style on the specified (pseudo-) element might
    112  // have changed so that any context-sensitive values stored within
    113  // animation effects (e.g. em-based endpoints used in keyframe effects)
    114  // can be re-resolved to computed values.
    115  void UpdateEffectProperties(const ComputedStyle* aStyle,
    116                              dom::Element* aElement,
    117                              const PseudoStyleRequest& aPseudoRequest);
    118 
    119  // Get the animation rule for the appropriate level of the cascade for
    120  // a (pseudo-)element. Called from the Servo side.
    121  //
    122  // The animation rule is stored in |StyleAnimationValueMap|.
    123  // We need to be careful while doing any modification because it may cause
    124  // some thread-safe issues.
    125  bool GetServoAnimationRule(const dom::Element* aElement,
    126                             const PseudoStyleRequest& aPseudoRequest,
    127                             CascadeLevel aCascadeLevel,
    128                             StyleAnimationValueMap* aAnimationValues);
    129 
    130  // A variant on GetServoAnimationRule that composes all the effects for an
    131  // element up to and including |aEffect|.
    132  //
    133  // Note that |aEffect| might not be in the EffectSet since we can use this for
    134  // committing the computed style of a removed Animation.
    135  bool ComposeServoAnimationRuleForEffect(
    136      dom::KeyframeEffect& aEffect, CascadeLevel aCascadeLevel,
    137      StyleAnimationValueMap* aAnimationValues,
    138      dom::EndpointBehavior aEndpointBehavior =
    139          dom::EndpointBehavior::Exclusive);
    140 
    141  bool HasPendingStyleUpdates() const;
    142 
    143  static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
    144                                         DisplayItemType aType);
    145 
    146  static nsTArray<RefPtr<dom::Animation>> GetAnimationsForCompositor(
    147      const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet);
    148 
    149  static void ClearIsRunningOnCompositor(const nsIFrame* aFrame,
    150                                         DisplayItemType aType);
    151 
    152  // Update animation cascade results for the specified (pseudo-)element
    153  // but only if we have marked the cascade as needing an update due a
    154  // the change in the set of effects or a change in one of the effects'
    155  // "in effect" state.
    156  //
    157  // This method does NOT detect if other styles that apply above the
    158  // animation level of the cascade have changed.
    159  static void MaybeUpdateCascadeResults(
    160      dom::Element* aElement, const PseudoStyleRequest& aPseudoRequest);
    161 
    162  // Update the mPropertiesWithImportantRules and
    163  // mPropertiesForAnimationsLevel members of the given EffectSet, and also
    164  // request any restyles required by changes to the cascade result.
    165  //
    166  // NOTE: This can be expensive so we should only call it if styles that apply
    167  // above the animation level of the cascade might have changed. For all
    168  // other cases we should call MaybeUpdateCascadeResults.
    169  //
    170  // This is typically reserved for internal callers but is public here since
    171  // when we detect changes to the cascade on the Servo side we can't call
    172  // MarkCascadeNeedsUpdate during the traversal so instead we call this as part
    173  // of a follow-up sequential task.
    174  static void UpdateCascadeResults(EffectSet& aEffectSet,
    175                                   dom::Element* aElement,
    176                                   const PseudoStyleRequest& aPseudoRequest);
    177 
    178  // Helper to fetch the corresponding element and pseudo-type from a frame.
    179  //
    180  // For frames corresponding to pseudo-elements, the returned element is the
    181  // element on which we store the animations (i.e. the EffectSet and/or
    182  // AnimationCollection), *not* the generated content.
    183  //
    184  // For display:table content, which maintains a distinction between primary
    185  // frame (table wrapper frame) and style frame (inner table frame), animations
    186  // are stored on the content associated with the _style_ frame even though
    187  // some (particularly transform-like animations) may be applied to the
    188  // _primary_ frame. As a result, callers will typically want to pass the style
    189  // frame to this function.
    190  //
    191  // Returns an empty result when a suitable element cannot be found including
    192  // when the frame represents a pseudo-element on which we do not support
    193  // animations.
    194  static Maybe<NonOwningAnimationTarget> GetAnimationElementAndPseudoForFrame(
    195      const nsIFrame* aFrame);
    196 
    197  // Associates a performance warning with effects on |aFrame| that animate
    198  // properties in |aPropertySet|.
    199  static void SetPerformanceWarning(
    200      const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
    201      const AnimationPerformanceWarning& aWarning);
    202 
    203  // Do a bunch of stuff that we should avoid doing during the parallel
    204  // traversal (e.g. changing member variables) for all elements that we expect
    205  // to restyle on the next traversal.
    206  //
    207  // Returns true if there are elements needing a restyle for animation.
    208  bool PreTraverse(ServoTraversalFlags aFlags);
    209 
    210  // Similar to the above but for all elements in the subtree rooted
    211  // at aElement.
    212  bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
    213 
    214  // Record a (pseudo-)element that may have animations that can be removed.
    215  void NoteElementForReducing(const NonOwningAnimationTarget& aTarget);
    216 
    217  bool NeedsReducing() const { return !mElementsToReduce.empty(); }
    218  void ReduceAnimations();
    219 
    220  // Returns true if any type of compositor animations on |aFrame| allow
    221  // runnning on the compositor.
    222  // Sets the reason in |aWarning| if the result is false.
    223  static bool AllowCompositorAnimationsOnFrame(
    224      const nsIFrame* aFrame,
    225      AnimationPerformanceWarning::Type& aWarning /* out */);
    226 
    227 private:
    228  ~EffectCompositor() = default;
    229 
    230  // Get the properties in |aEffectSet| that we are able to animate on the
    231  // compositor but which are also specified at a higher level in the cascade
    232  // than the animations level.
    233  static nsCSSPropertyIDSet GetOverriddenProperties(
    234      EffectSet& aEffectSet, dom::Element* aElement,
    235      const PseudoStyleRequest& aPseudoRequest);
    236 
    237  static nsPresContext* GetPresContext(dom::Element* aElement);
    238 
    239  nsPresContext* mPresContext;
    240 
    241  // Elements with a pending animation restyle. The associated bool value is
    242  // true if a pending animation restyle has also been dispatched. For
    243  // animations that can be throttled, we will add an entry to the hashtable to
    244  // indicate that the style rule on the element is out of date but without
    245  // posting a restyle to update it.
    246  EnumeratedArray<CascadeLevel, nsTHashMap<PseudoElementHashEntry, bool>,
    247                  kCascadeLevelCount>
    248      mElementsToRestyle;
    249 
    250  bool mIsInPreTraverse = false;
    251 
    252  HashSet<OwningAnimationTarget> mElementsToReduce;
    253 };
    254 
    255 }  // namespace mozilla
    256 
    257 #endif  // mozilla_EffectCompositor_h