Source code

Revision control

Other Tools

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_layers_AnimationHelper_h
8
#define mozilla_layers_AnimationHelper_h
9
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"
18
19
namespace mozilla {
20
struct AnimationValue;
21
22
namespace dom {
23
enum class CompositeOperation : uint8_t;
24
enum class IterationCompositeOperation : uint8_t;
25
}; // namespace dom
26
27
namespace layers {
28
class Animation;
29
30
typedef nsTArray<layers::Animation> AnimationArray;
31
32
struct PropertyAnimation {
33
struct SegmentData {
34
RefPtr<RawServoAnimationValue> mStartValue;
35
RefPtr<RawServoAnimationValue> mEndValue;
36
Maybe<mozilla::ComputedTimingFunction> mFunction;
37
float mStartPortion;
38
float mEndPortion;
39
dom::CompositeOperation mStartComposite;
40
dom::CompositeOperation mEndComposite;
41
};
42
nsTArray<SegmentData> mSegments;
43
TimingParams mTiming;
44
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;
54
55
TimeStamp mOriginTime;
56
Maybe<TimeDuration> mStartTime;
57
TimeDuration mHoldTime;
58
float mPlaybackRate;
59
dom::IterationCompositeOperation mIterationComposite;
60
bool mIsNotPlaying;
61
};
62
63
struct PropertyAnimationGroup {
64
nsCSSPropertyID mProperty;
65
66
nsTArray<PropertyAnimation> mAnimations;
67
RefPtr<RawServoAnimationValue> mBaseStyle;
68
69
bool IsEmpty() const { return mAnimations.IsEmpty(); }
70
void Clear() {
71
mAnimations.Clear();
72
mBaseStyle = nullptr;
73
}
74
};
75
76
struct AnimationTransform {
77
/*
78
* This transform is calculated from sampleanimation in device pixel
79
* and used by compositor.
80
*/
81
gfx::Matrix4x4 mTransformInDevSpace;
82
/*
83
* This transform is calculated from frame and used by getOMTAStyle()
84
* for OMTA testing.
85
*/
86
gfx::Matrix4x4 mFrameTransform;
87
TransformData mData;
88
};
89
90
struct AnimatedValue final {
91
typedef Variant<AnimationTransform, float, nscolor> AnimatedValueType;
92
93
const AnimatedValueType& Value() const { return mValue; }
94
const AnimationTransform& Transform() const {
95
return mValue.as<AnimationTransform>();
96
}
97
const float& Opacity() const { return mValue.as<float>(); }
98
const nscolor& Color() const { return mValue.as<nscolor>(); }
99
template <typename T>
100
bool Is() const {
101
return mValue.is<T>();
102
}
103
104
AnimatedValue(gfx::Matrix4x4&& aTransformInDevSpace,
105
gfx::Matrix4x4&& aFrameTransform, const TransformData& aData)
106
: mValue(
107
AsVariant(AnimationTransform{std::move(aTransformInDevSpace),
108
std::move(aFrameTransform), aData})) {}
109
110
explicit AnimatedValue(const float& aValue) : mValue(AsVariant(aValue)) {}
111
112
explicit AnimatedValue(nscolor aValue) : mValue(AsVariant(aValue)) {}
113
114
private:
115
AnimatedValueType mValue;
116
};
117
118
struct AnimationStorageData {
119
nsTArray<PropertyAnimationGroup> mAnimation;
120
Maybe<TransformData> mTransformData;
121
RefPtr<gfx::Path> mCachedMotionPath;
122
123
AnimationStorageData() = default;
124
AnimationStorageData(AnimationStorageData&& aOther) = default;
125
AnimationStorageData& operator=(AnimationStorageData&& aOther) = default;
126
127
// Avoid any copy because mAnimation could be a large array.
128
AnimationStorageData(const AnimationStorageData& aOther) = delete;
129
AnimationStorageData& operator=(const AnimationStorageData& aOther) = delete;
130
};
131
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.
136
//
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.
140
//
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
145
// mechanism).
146
class CompositorAnimationStorage final {
147
typedef nsClassHashtable<nsUint64HashKey, AnimatedValue> AnimatedValueTable;
148
typedef nsDataHashtable<nsUint64HashKey, AnimationStorageData>
149
AnimationsTable;
150
typedef nsDataHashtable<nsUint64HashKey, wr::RenderRoot>
151
AnimationsRenderRootsTable;
152
153
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorAnimationStorage)
154
public:
155
/**
156
* Set the animation transform based on the unique id and also
157
* set up |aFrameTransform| and |aData| for OMTA testing
158
*/
159
void SetAnimatedValue(uint64_t aId, gfx::Matrix4x4&& aTransformInDevSpace,
160
gfx::Matrix4x4&& aFrameTransform,
161
const TransformData& aData);
162
163
/**
164
* Set the animation transform in device pixel based on the unique id
165
*/
166
void SetAnimatedValue(uint64_t aId, gfx::Matrix4x4&& aTransformInDevSpace);
167
168
/**
169
* Set the animation opacity based on the unique id
170
*/
171
void SetAnimatedValue(uint64_t aId, const float& aOpacity);
172
173
/**
174
* Set the animation color based on the unique id
175
*/
176
void SetAnimatedValue(uint64_t aId, nscolor aColor);
177
178
/**
179
* Return the animated value if a given id can map to its animated value
180
*/
181
AnimatedValue* GetAnimatedValue(const uint64_t& aId) const;
182
183
OMTAValue GetOMTAValue(const uint64_t& aId) const;
184
185
/**
186
* Return the iterator of animated value table
187
*/
188
AnimatedValueTable::Iterator ConstAnimatedValueTableIter() const {
189
return mAnimatedValues.ConstIter();
190
}
191
192
uint32_t AnimatedValueCount() const { return mAnimatedValues.Count(); }
193
194
/**
195
* Set the animations based on the unique id
196
*/
197
void SetAnimations(uint64_t aId, const AnimationArray& aAnimations,
198
wr::RenderRoot aRenderRoot);
199
200
/**
201
* Return the iterator of animations table
202
*/
203
AnimationsTable::Iterator ConstAnimationsTableIter() const {
204
return mAnimations.ConstIter();
205
}
206
207
uint32_t AnimationsCount() const { return mAnimations.Count(); }
208
209
wr::RenderRoot AnimationRenderRoot(const uint64_t& aId) const {
210
return mAnimationRenderRoots.Get(aId);
211
}
212
213
/**
214
* Clear AnimatedValues and Animations data
215
*/
216
void Clear();
217
void ClearById(const uint64_t& aId);
218
219
private:
220
~CompositorAnimationStorage(){};
221
222
private:
223
AnimatedValueTable mAnimatedValues;
224
AnimationsTable mAnimations;
225
AnimationsRenderRootsTable mAnimationRenderRoots;
226
};
227
228
/**
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.
232
*/
233
class AnimationHelper {
234
public:
235
enum class SampleResult { None, Skipped, Sampled };
236
237
/**
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.
245
*
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.
251
*
252
* Using the same example from ExtractAnimations (below):
253
*
254
* Input |aPropertyAnimationGroups| (ignoring the base animation style):
255
*
256
* [
257
* Group A: [ { rotate, Animation A }, { rotate, Animation B } ],
258
* Group B: [ { scale, Animation B } ],
259
* Group C: [ { transform, Animation A }, { transform, Animation B } ],
260
* ]
261
*
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:
265
*
266
* [
267
* { rotate, RawServoAnimationValue },
268
* { scale, RawServoAnimationValue },
269
* { transform, RawServoAnimationValue },
270
* ]
271
*
272
* For transform animations, the caller (SampleAnimations) will combine the
273
* result of the various transform properties into a final matrix.
274
*/
275
static SampleResult SampleAnimationForEachNode(
276
TimeStamp aPreviousFrameTime, TimeStamp aCurrentFrameTime,
277
const AnimatedValue* aPreviousValue,
278
nsTArray<PropertyAnimationGroup>& aPropertyAnimationGroups,
279
nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues);
280
281
/**
282
* Extract organized animation data by property into an array of
283
* PropertyAnimationGroup objects.
284
*
285
* For example, suppose we have the following animations:
286
*
287
* Animation A: [ transform, rotate ]
288
* Animation B: [ rotate, scale ]
289
* Animation C: [ transform ]
290
* Animation D: [ opacity ]
291
*
292
* When we go to send transform-like properties to the compositor, we
293
* sort them as follows:
294
*
295
* [
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 ( " " ) },
301
* ]
302
*
303
* In this function, we group these animations together by property producing
304
* output such as the following:
305
*
306
* [
307
* [ { rotate, Animation A }, { rotate, Animation B } ],
308
* [ { scale, Animation B } ],
309
* [ { transform, Animation A }, { transform, Animation B } ],
310
* ]
311
*
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.
315
*/
316
static AnimationStorageData ExtractAnimations(
317
const AnimationArray& aAnimations);
318
319
/**
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
324
* data.
325
*/
326
static uint64_t GetNextCompositorAnimationsId();
327
328
/**
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.
332
*
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.
337
*
338
* Note: This is called only by WebRender.
339
*/
340
static bool SampleAnimations(CompositorAnimationStorage* aStorage,
341
TimeStamp aPreviousFrameTime,
342
TimeStamp aCurrentFrameTime);
343
344
/**
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.).
348
*/
349
static gfx::Matrix4x4 ServoAnimationValueToMatrix4x4(
350
const nsTArray<RefPtr<RawServoAnimationValue>>& aValue,
351
const TransformData& aTransformData, gfx::Path* aCachedMotionPath);
352
};
353
354
} // namespace layers
355
} // namespace mozilla
356
357
#endif // mozilla_layers_AnimationHelper_h