Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / gfx / layers / AnimationHelper.h
blob71c86a4893012f86285f13c88ef56957fa922f76
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"
19 namespace mozilla {
20 struct AnimationValue;
22 namespace dom {
23 enum class CompositeOperation : uint8_t;
24 enum class IterationCompositeOperation : uint8_t;
25 }; // namespace dom
27 namespace layers {
28 class Animation;
30 typedef nsTArray<layers::Animation> AnimationArray;
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;
42 nsTArray<SegmentData> mSegments;
43 TimingParams mTiming;
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;
58 float mPlaybackRate;
59 dom::IterationCompositeOperation mIterationComposite;
60 bool mIsNotPlaying;
63 struct PropertyAnimationGroup {
64 nsCSSPropertyID mProperty;
66 nsTArray<PropertyAnimation> mAnimations;
67 RefPtr<RawServoAnimationValue> mBaseStyle;
69 bool IsEmpty() const { return mAnimations.IsEmpty(); }
70 void Clear() {
71 mAnimations.Clear();
72 mBaseStyle = nullptr;
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()
84 * for OMTA testing.
86 gfx::Matrix4x4 mFrameTransform;
87 TransformData mData;
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>(); }
99 template <typename T>
100 bool Is() const {
101 return mValue.is<T>();
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})) {}
110 explicit AnimatedValue(const float& aValue) : mValue(AsVariant(aValue)) {}
112 explicit AnimatedValue(nscolor aValue) : mValue(AsVariant(aValue)) {}
114 private:
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
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;
153 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorAnimationStorage)
154 public:
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
216 void Clear();
217 void ClearById(const uint64_t& aId);
219 private:
220 ~CompositorAnimationStorage(){};
222 private:
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 {
234 public:
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
324 * data.
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