/* -*- 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_layers_CompositorAnimationStorage_h #define mozilla_layers_CompositorAnimationStorage_h #include "mozilla/layers/AnimationStorageData.h" #include "mozilla/layers/LayersMessages.h" // for TransformData, etc #include "mozilla/webrender/webrender_ffi.h" #include "mozilla/Variant.h" #include "nsClassHashtable.h" #include "X11UndefineNone.h" #include #include #include namespace mozilla { namespace layers { class Animation; class CompositorBridgeParent; class Layer; class OMTAController; typedef nsTArray AnimationArray; struct AnimationTransform { /* * This transform is calculated from sampleanimation in device pixel * and used for layers (i.e. non WebRender) */ gfx::Matrix4x4 mTransformInDevSpace; /* * This transform is calculated from frame used for WebRender and used by * getOMTAStyle() for OMTA testing. */ gfx::Matrix4x4 mFrameTransform; TransformData mData; }; struct AnimatedValue final { typedef Variant AnimatedValueType; const AnimatedValueType& Value() const { return mValue; } const AnimationTransform& Transform() const { return mValue.as(); } const float& Opacity() const { return mValue.as(); } const nscolor& Color() const { return mValue.as(); } template bool Is() const { return mValue.is(); } AnimatedValue(const gfx::Matrix4x4& aTransformInDevSpace, const gfx::Matrix4x4& aFrameTransform, const TransformData& aData) : mValue(AsVariant(AnimationTransform{aTransformInDevSpace, aFrameTransform, aData})) {} explicit AnimatedValue(const float& aValue) : mValue(AsVariant(aValue)) {} explicit AnimatedValue(nscolor aValue) : mValue(AsVariant(aValue)) {} void SetTransformForWebRender(const gfx::Matrix4x4& aFrameTransform, const TransformData& aData) { MOZ_ASSERT(mValue.is()); AnimationTransform& previous = mValue.as(); previous.mFrameTransform = aFrameTransform; if (previous.mData != aData) { previous.mData = aData; } } void SetTransform(const gfx::Matrix4x4& aTransformInDevSpace, const gfx::Matrix4x4& aFrameTransform, const TransformData& aData) { MOZ_ASSERT(mValue.is()); AnimationTransform& previous = mValue.as(); previous.mTransformInDevSpace = aTransformInDevSpace; previous.mFrameTransform = aFrameTransform; if (previous.mData != aData) { previous.mData = aData; } } void SetOpacity(float aOpacity) { MOZ_ASSERT(mValue.is()); mValue.as() = aOpacity; } void SetColor(nscolor aColor) { MOZ_ASSERT(mValue.is()); mValue.as() = aColor; } private: AnimatedValueType mValue; }; struct WrAnimations { nsTArray mOpacityArrays; nsTArray mTransformArrays; nsTArray mColorArrays; }; // CompositorAnimationStorage stores the animations and animated values // keyed by a CompositorAnimationsId. The "animations" are a representation of // an entire animation over time, while the "animated values" are values sampled // from the animations at a particular point in time. // // There is one CompositorAnimationStorage per CompositorBridgeParent (i.e. // one per browser window), and the CompositorAnimationsId key is unique within // a particular CompositorAnimationStorage instance. // // Each layer which has animations gets a CompositorAnimationsId key, and reuses // that key during its lifetime. Likewise, in layers-free webrender, a display // item that is animated (e.g. nsDisplayTransform) gets a CompositorAnimationsId // key and reuses that key (it persists the key via the frame user-data // mechanism). class CompositorAnimationStorage final { typedef nsClassHashtable AnimatedValueTable; typedef std::unordered_map> AnimationsTable; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorAnimationStorage) public: explicit CompositorAnimationStorage(CompositorBridgeParent* aCompositorBridge) : mLock("CompositorAnimationStorage::mLock"), mCompositorBridge(aCompositorBridge) {} OMTAValue GetOMTAValue(const uint64_t& aId) const; /** * Collect all animations in this class as WebRender type properties. */ WrAnimations CollectWebRenderAnimations() const; /** * Set the animations based on the unique id */ void SetAnimations(uint64_t aId, const LayersId& aLayersId, const AnimationArray& aAnimations); /** * Sample animation based the given timestamps and store them in this * CompositorAnimationStorage. The animated values after sampling will be * stored in CompositorAnimationStorage as well. * * Returns true if there is any animation. * Note that even if there are only in-delay phase animations (i.e. not * visually effective), this function returns true to ensure we composite * again on the next tick. * * Note: This is called only by WebRender. */ bool SampleAnimations(const OMTAController* aOMTAController, TimeStamp aPreviousFrameTime, TimeStamp aCurrentFrameTime); /** * Non WebRender version of above SampleAnimations. * * Note: This is called only by non WebRender. */ bool SampleAnimations(Layer* aRoot, CompositorBridgeParent* aCompositorBridge, TimeStamp aPreviousFrameTime, TimeStamp aCurrentFrameTime); bool HasAnimations() const; /** * Clear AnimatedValues and Animations data */ void ClearById(const uint64_t& aId); private: ~CompositorAnimationStorage() = default; /** * Return the animated value if a given id can map to its animated value */ AnimatedValue* GetAnimatedValue(const uint64_t& aId) const; /** * Set the animation transform based on the unique id and also * set up |aFrameTransform| and |aData| for OMTA testing. * If |aPreviousValue| is not null, the animation transform replaces the value * in the |aPreviousValue|. * NOTE: |aPreviousValue| should be the value for the |aId|. */ void SetAnimatedValue(uint64_t aId, AnimatedValue* aPreviousValue, const gfx::Matrix4x4& aTransformInDevSpace, const gfx::Matrix4x4& aFrameTransform, const TransformData& aData); /** * This is for the WebRender version of above SetAnimatedValue. * In the case of WebRender we don't need to have |aTransformInDevSpace| * separately because it's same as |aFrameTransform|. */ void SetAnimatedValueForWebRender(uint64_t aId, AnimatedValue* aPreviousValue, const gfx::Matrix4x4& aFrameTransform, const TransformData& aData); /** * Similar to above but for opacity. */ void SetAnimatedValue(uint64_t aId, AnimatedValue* aPreviousValue, float aOpacity); /** * Similar to above but for color. */ void SetAnimatedValue(uint64_t aId, AnimatedValue* aPreviousValue, nscolor aColor); bool ApplyAnimatedValue( CompositorBridgeParent* aCompositorBridge, Layer* aLayer, nsCSSPropertyID aProperty, AnimatedValue* aPreviousValue, const nsTArray>& aValues); void Clear(); private: AnimatedValueTable mAnimatedValues; AnimationsTable mAnimations; std::unordered_set mNewAnimations; mutable Mutex mLock; // CompositorBridgeParent owns this CompositorAnimationStorage instance. CompositorBridgeParent* MOZ_NON_OWNING_REF mCompositorBridge; }; } // namespace layers } // namespace mozilla #endif // mozilla_layers_CompositorAnimationStorage_h