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/. */
7 #ifndef mozilla_layers_AnimationHelper_h
8 #define mozilla_layers_AnimationHelper_h
10 #include "mozilla/dom/Nullable.h"
11 #include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
12 #include "mozilla/layers/LayersMessages.h" // for TransformData, etc
13 #include "mozilla/webrender/WebRenderTypes.h" // for RenderRoot
14 #include "mozilla/TimeStamp.h" // for TimeStamp
15 #include "mozilla/TimingParams.h"
16 #include "mozilla/Variant.h"
17 #include "X11UndefineNone.h"
20 struct AnimationValue
;
23 enum class CompositeOperation
: uint8_t;
24 enum class IterationCompositeOperation
: uint8_t;
30 typedef nsTArray
<layers::Animation
> AnimationArray
;
32 struct PropertyAnimation
{
34 RefPtr
<RawServoAnimationValue
> mStartValue
;
35 RefPtr
<RawServoAnimationValue
> mEndValue
;
36 Maybe
<mozilla::ComputedTimingFunction
> mFunction
;
39 dom::CompositeOperation mStartComposite
;
40 dom::CompositeOperation mEndComposite
;
42 nsTArray
<SegmentData
> mSegments
;
45 // These two variables correspond to the variables of the same name in
46 // KeyframeEffectReadOnly and are used for the same purpose: to skip composing
47 // animations whose progress has not changed.
48 dom::Nullable
<double> mProgressOnLastCompose
;
49 uint64_t mCurrentIterationOnLastCompose
= 0;
50 // These two variables are used for a similar optimization above but are
51 // applied to the timing function in each keyframe.
52 uint32_t mSegmentIndexOnLastCompose
= 0;
53 dom::Nullable
<double> mPortionInSegmentOnLastCompose
;
55 TimeStamp mOriginTime
;
56 Maybe
<TimeDuration
> mStartTime
;
57 TimeDuration mHoldTime
;
59 dom::IterationCompositeOperation mIterationComposite
;
63 struct PropertyAnimationGroup
{
64 nsCSSPropertyID mProperty
;
66 nsTArray
<PropertyAnimation
> mAnimations
;
67 RefPtr
<RawServoAnimationValue
> mBaseStyle
;
69 bool IsEmpty() const { return mAnimations
.IsEmpty(); }
76 struct AnimationTransform
{
78 * This transform is calculated from sampleanimation in device pixel
79 * and used by compositor.
81 gfx::Matrix4x4 mTransformInDevSpace
;
83 * This transform is calculated from frame and used by getOMTAStyle()
86 gfx::Matrix4x4 mFrameTransform
;
90 struct AnimatedValue final
{
91 typedef Variant
<AnimationTransform
, float, nscolor
> AnimatedValueType
;
93 const AnimatedValueType
& Value() const { return mValue
; }
94 const AnimationTransform
& Transform() const {
95 return mValue
.as
<AnimationTransform
>();
97 const float& Opacity() const { return mValue
.as
<float>(); }
98 const nscolor
& Color() const { return mValue
.as
<nscolor
>(); }
101 return mValue
.is
<T
>();
104 AnimatedValue(gfx::Matrix4x4
&& aTransformInDevSpace
,
105 gfx::Matrix4x4
&& aFrameTransform
, const TransformData
& aData
)
107 AsVariant(AnimationTransform
{std::move(aTransformInDevSpace
),
108 std::move(aFrameTransform
), aData
})) {}
110 explicit AnimatedValue(const float& aValue
) : mValue(AsVariant(aValue
)) {}
112 explicit AnimatedValue(nscolor aValue
) : mValue(AsVariant(aValue
)) {}
115 AnimatedValueType mValue
;
118 struct AnimationStorageData
{
119 nsTArray
<PropertyAnimationGroup
> mAnimation
;
120 Maybe
<TransformData
> mTransformData
;
121 RefPtr
<gfx::Path
> mCachedMotionPath
;
123 AnimationStorageData() = default;
124 AnimationStorageData(AnimationStorageData
&& aOther
) = default;
125 AnimationStorageData
& operator=(AnimationStorageData
&& aOther
) = default;
127 // Avoid any copy because mAnimation could be a large array.
128 AnimationStorageData(const AnimationStorageData
& aOther
) = delete;
129 AnimationStorageData
& operator=(const AnimationStorageData
& aOther
) = delete;
132 // CompositorAnimationStorage stores the animations and animated values
133 // keyed by a CompositorAnimationsId. The "animations" are a representation of
134 // an entire animation over time, while the "animated values" are values sampled
135 // from the animations at a particular point in time.
137 // There is one CompositorAnimationStorage per CompositorBridgeParent (i.e.
138 // one per browser window), and the CompositorAnimationsId key is unique within
139 // a particular CompositorAnimationStorage instance.
141 // Each layer which has animations gets a CompositorAnimationsId key, and reuses
142 // that key during its lifetime. Likewise, in layers-free webrender, a display
143 // item that is animated (e.g. nsDisplayTransform) gets a CompositorAnimationsId
144 // key and reuses that key (it persists the key via the frame user-data
146 class CompositorAnimationStorage final
{
147 typedef nsClassHashtable
<nsUint64HashKey
, AnimatedValue
> AnimatedValueTable
;
148 typedef nsDataHashtable
<nsUint64HashKey
, AnimationStorageData
>
150 typedef nsDataHashtable
<nsUint64HashKey
, wr::RenderRoot
>
151 AnimationsRenderRootsTable
;
153 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorAnimationStorage
)
156 * Set the animation transform based on the unique id and also
157 * set up |aFrameTransform| and |aData| for OMTA testing
159 void SetAnimatedValue(uint64_t aId
, gfx::Matrix4x4
&& aTransformInDevSpace
,
160 gfx::Matrix4x4
&& aFrameTransform
,
161 const TransformData
& aData
);
164 * Set the animation transform in device pixel based on the unique id
166 void SetAnimatedValue(uint64_t aId
, gfx::Matrix4x4
&& aTransformInDevSpace
);
169 * Set the animation opacity based on the unique id
171 void SetAnimatedValue(uint64_t aId
, const float& aOpacity
);
174 * Set the animation color based on the unique id
176 void SetAnimatedValue(uint64_t aId
, nscolor aColor
);
179 * Return the animated value if a given id can map to its animated value
181 AnimatedValue
* GetAnimatedValue(const uint64_t& aId
) const;
183 OMTAValue
GetOMTAValue(const uint64_t& aId
) const;
186 * Return the iterator of animated value table
188 AnimatedValueTable::Iterator
ConstAnimatedValueTableIter() const {
189 return mAnimatedValues
.ConstIter();
192 uint32_t AnimatedValueCount() const { return mAnimatedValues
.Count(); }
195 * Set the animations based on the unique id
197 void SetAnimations(uint64_t aId
, const AnimationArray
& aAnimations
,
198 wr::RenderRoot aRenderRoot
);
201 * Return the iterator of animations table
203 AnimationsTable::Iterator
ConstAnimationsTableIter() const {
204 return mAnimations
.ConstIter();
207 uint32_t AnimationsCount() const { return mAnimations
.Count(); }
209 wr::RenderRoot
AnimationRenderRoot(const uint64_t& aId
) const {
210 return mAnimationRenderRoots
.Get(aId
);
214 * Clear AnimatedValues and Animations data
217 void ClearById(const uint64_t& aId
);
220 ~CompositorAnimationStorage(){};
223 AnimatedValueTable mAnimatedValues
;
224 AnimationsTable mAnimations
;
225 AnimationsRenderRootsTable mAnimationRenderRoots
;
229 * This utility class allows reusing code between the webrender and
230 * non-webrender compositor-side implementations. It provides
231 * utility functions for sampling animations at particular timestamps.
233 class AnimationHelper
{
235 enum class SampleResult
{ None
, Skipped
, Sampled
};
238 * Sample animations based on a given time stamp for a element(layer) with
239 * its animation data.
240 * Generally |aPreviousFrameTime| is used for the sampling if it's
241 * supplied to make the animation more in sync with other animations on the
242 * main-thread. But in the case where the animation just started at the time
243 * when the animation was sent to the compositor, |aCurrentFrameTime| is used
244 * for sampling instead to avoid flicker.
246 * Returns SampleResult::None if none of the animations are producing a result
247 * (e.g. they are in the delay phase with no backwards fill),
248 * SampleResult::Skipped if the animation output did not change since the last
249 * call of this function,
250 * SampleResult::Sampled if the animation output was updated.
252 * Using the same example from ExtractAnimations (below):
254 * Input |aPropertyAnimationGroups| (ignoring the base animation style):
257 * Group A: [ { rotate, Animation A }, { rotate, Animation B } ],
258 * Group B: [ { scale, Animation B } ],
259 * Group C: [ { transform, Animation A }, { transform, Animation B } ],
262 * For each property group, this function interpolates each animation in turn,
263 * using the result of interpolating one animation as input for the next such
264 * that it reduces each property group to a single output value:
267 * { rotate, RawServoAnimationValue },
268 * { scale, RawServoAnimationValue },
269 * { transform, RawServoAnimationValue },
272 * For transform animations, the caller (SampleAnimations) will combine the
273 * result of the various transform properties into a final matrix.
275 static SampleResult
SampleAnimationForEachNode(
276 TimeStamp aPreviousFrameTime
, TimeStamp aCurrentFrameTime
,
277 const AnimatedValue
* aPreviousValue
,
278 nsTArray
<PropertyAnimationGroup
>& aPropertyAnimationGroups
,
279 nsTArray
<RefPtr
<RawServoAnimationValue
>>& aAnimationValues
);
282 * Extract organized animation data by property into an array of
283 * PropertyAnimationGroup objects.
285 * For example, suppose we have the following animations:
287 * Animation A: [ transform, rotate ]
288 * Animation B: [ rotate, scale ]
289 * Animation C: [ transform ]
290 * Animation D: [ opacity ]
292 * When we go to send transform-like properties to the compositor, we
293 * sort them as follows:
296 * { rotate: Animation A (rotate segments only) },
297 * { rotate: Animation B ( " " ) },
298 * { scale: Animation B (scale segments only) },
299 * { transform: Animation A (transform segments only) },
300 * { transform: Animation C ( " " ) },
303 * In this function, we group these animations together by property producing
304 * output such as the following:
307 * [ { rotate, Animation A }, { rotate, Animation B } ],
308 * [ { scale, Animation B } ],
309 * [ { transform, Animation A }, { transform, Animation B } ],
312 * In the process of grouping these animations, we also convert their values
313 * from the rather compact representation we use for transferring across the
314 * IPC boundary into something we can readily use for sampling.
316 static AnimationStorageData
ExtractAnimations(
317 const AnimationArray
& aAnimations
);
320 * Get a unique id to represent the compositor animation between child
321 * and parent side. This id will be used as a key to store animation
322 * data in the CompositorAnimationStorage per compositor.
323 * Each layer on the content side calls this when it gets new animation
326 static uint64_t GetNextCompositorAnimationsId();
329 * Sample animation based a given time stamp |aTime| and the animation
330 * data inside CompositorAnimationStorage |aStorage|. The animated values
331 * after sampling will be stored in CompositorAnimationStorage as well.
333 * Returns true if there is any animation.
334 * Note that even if there are only in-delay phase animations (i.e. not
335 * visually effective), this function returns true to ensure we composite
336 * again on the next tick.
338 * Note: This is called only by WebRender.
340 static bool SampleAnimations(CompositorAnimationStorage
* aStorage
,
341 TimeStamp aPreviousFrameTime
,
342 TimeStamp aCurrentFrameTime
);
345 * Convert an array of animation values into a matrix given the corresponding
346 * transform parameters. |aValue| must be a transform-like value
347 * (e.g. transform, translate etc.).
349 static gfx::Matrix4x4
ServoAnimationValueToMatrix4x4(
350 const nsTArray
<RefPtr
<RawServoAnimationValue
>>& aValue
,
351 const TransformData
& aTransformData
, gfx::Path
* aCachedMotionPath
);
354 } // namespace layers
355 } // namespace mozilla
357 #endif // mozilla_layers_AnimationHelper_h