AnimationHelper.h (7398B)
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/layers/AnimationStorageData.h" 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 "X11UndefineNone.h" 17 18 namespace mozilla::layers { 19 class Animation; 20 class APZSampler; 21 class CompositorAnimationStorage; 22 struct AnimatedValue; 23 24 using AnimationArray = nsTArray<layers::Animation>; 25 using SampledAnimationArray = AutoTArray<RefPtr<StyleAnimationValue>, 1>; 26 27 /** 28 * This utility class allows reusing code between the webrender and 29 * non-webrender compositor-side implementations. It provides 30 * utility functions for sampling animations at particular timestamps. 31 */ 32 class AnimationHelper { 33 public: 34 struct SampleResult { 35 enum class Type : uint8_t { None, Skipped, Sampled }; 36 enum class Reason : uint8_t { None, ScrollToDelayPhase }; 37 Type mType = Type::None; 38 Reason mReason = Reason::None; 39 40 SampleResult() = default; 41 SampleResult(Type aType, Reason aReason) : mType(aType), mReason(aReason) {} 42 43 static SampleResult Skipped() { return {Type::Skipped, Reason::None}; } 44 static SampleResult Sampled() { return {Type::Sampled, Reason::None}; } 45 46 bool IsNone() { return mType == Type::None; } 47 bool IsSkipped() { return mType == Type::Skipped; } 48 bool IsSampled() { return mType == Type::Sampled; } 49 }; 50 51 /** 52 * Sample animations based on a given time stamp for a element(layer) with 53 * its animation data. 54 * Generally |aPreviousFrameTime| is used for the sampling if it's 55 * supplied to make the animation more in sync with other animations on the 56 * main-thread. But in the case where the animation just started at the time 57 * when the animation was sent to the compositor, |aCurrentFrameTime| is used 58 * for sampling instead to avoid flicker. 59 * 60 * Returns SampleResult::None if none of the animations are producing a result 61 * (e.g. they are in the delay phase with no backwards fill), 62 * SampleResult::Skipped if the animation output did not change since the last 63 * call of this function, 64 * SampleResult::Sampled if the animation output was updated. 65 * 66 * The only exception is the scroll-driven animation. When the user move the 67 * scrollbar to make the animations go from active phase to delay phase, this 68 * returns SampleResult::None but sets its |mReason| to 69 * Reason::ScrollToDelayPhase. The caller can check this flag so we can store 70 * the base style into the hash table to make sure we have the correct 71 * rendering result. The base style stays in the hash table until we sync with 72 * main thread. 73 * 74 * Using the same example from ExtractAnimations (below): 75 * 76 * Input |aPropertyAnimationGroups| (ignoring the base animation style): 77 * 78 * [ 79 * Group A: [ { rotate, Animation A }, { rotate, Animation B } ], 80 * Group B: [ { scale, Animation B } ], 81 * Group C: [ { transform, Animation A }, { transform, Animation B } ], 82 * ] 83 * 84 * For each property group, this function interpolates each animation in turn, 85 * using the result of interpolating one animation as input for the next such 86 * that it reduces each property group to a single output value: 87 * 88 * [ 89 * { rotate, StyleAnimationValue }, 90 * { scale, StyleAnimationValue }, 91 * { transform, StyleAnimationValue }, 92 * ] 93 * 94 * For transform animations, the caller (SampleAnimations) will combine the 95 * result of the various transform properties into a final matrix. 96 */ 97 static SampleResult SampleAnimationForEachNode( 98 const APZSampler* aAPZSampler, const LayersId& aLayersId, 99 const MutexAutoLock& aProofOfMapLock, TimeStamp aPreviousFrameTime, 100 TimeStamp aCurrentFrameTime, const AnimatedValue* aPreviousValue, 101 nsTArray<PropertyAnimationGroup>& aPropertyAnimationGroups, 102 SampledAnimationArray& aAnimationValues /* output */); 103 104 /** 105 * Extract organized animation data by property into an array of 106 * PropertyAnimationGroup objects. 107 * 108 * For example, suppose we have the following animations: 109 * 110 * Animation A: [ transform, rotate ] 111 * Animation B: [ rotate, scale ] 112 * Animation C: [ transform ] 113 * Animation D: [ opacity ] 114 * 115 * When we go to send transform-like properties to the compositor, we 116 * sort them as follows: 117 * 118 * [ 119 * { rotate: Animation A (rotate segments only) }, 120 * { rotate: Animation B ( " " ) }, 121 * { scale: Animation B (scale segments only) }, 122 * { transform: Animation A (transform segments only) }, 123 * { transform: Animation C ( " " ) }, 124 * ] 125 * 126 * In this function, we group these animations together by property producing 127 * output such as the following: 128 * 129 * [ 130 * [ { rotate, Animation A }, { rotate, Animation B } ], 131 * [ { scale, Animation B } ], 132 * [ { transform, Animation A }, { transform, Animation B } ], 133 * ] 134 * 135 * In the process of grouping these animations, we also convert their values 136 * from the rather compact representation we use for transferring across the 137 * IPC boundary into something we can readily use for sampling. 138 * 139 * Note: the animation groups: 140 * 1. transform-like properties: transfrom, translate, rotate, scale, 141 * offset-*. 142 * 2. opacity property: opacity. 143 * 3. background color property: background-color. 144 */ 145 static AnimationStorageData ExtractAnimations( 146 const LayersId& aLayersId, const AnimationArray& aAnimations, 147 const CompositorAnimationStorage* aStorage, 148 const TimeStamp& aPreviousSampleTime); 149 150 /** 151 * Get a unique id to represent the compositor animation between child 152 * and parent side. This id will be used as a key to store animation 153 * data in the CompositorAnimationStorage per compositor. 154 * Each layer on the content side calls this when it gets new animation 155 * data. 156 */ 157 static uint64_t GetNextCompositorAnimationsId(); 158 159 /** 160 * Convert an array of animation values into a matrix given the corresponding 161 * transform parameters. |aValue| must be a transform-like value 162 * (e.g. transform, translate etc.). 163 */ 164 static gfx::Matrix4x4 ServoAnimationValueToMatrix4x4( 165 const SampledAnimationArray& aValue, const TransformData& aTransformData, 166 gfx::Path* aCachedMotionPath); 167 168 /** 169 * Returns true if |aPrerenderedRect| transformed by |aTransform| were 170 * composited in |aClipRect| there appears area which wasn't pre-rendered 171 * on the main-thread. I.e. checkerboarding. 172 */ 173 static bool ShouldBeJank(const LayoutDeviceRect& aPrerenderedRect, 174 SideBits aOverflowedSides, 175 const gfx::Matrix4x4& aTransform, 176 const ParentLayerRect& aClipRect); 177 }; 178 179 } // namespace mozilla::layers 180 181 #endif // mozilla_layers_AnimationHelper_h