diff options
Diffstat (limited to 'gfx/layers/AnimationHelper.h')
-rw-r--r-- | gfx/layers/AnimationHelper.h | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/gfx/layers/AnimationHelper.h b/gfx/layers/AnimationHelper.h new file mode 100644 index 0000000000..7afe9a7056 --- /dev/null +++ b/gfx/layers/AnimationHelper.h @@ -0,0 +1,180 @@ +/* -*- 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_AnimationHelper_h +#define mozilla_layers_AnimationHelper_h + +#include "mozilla/dom/Nullable.h" +#include "mozilla/layers/AnimationStorageData.h" +#include "mozilla/layers/LayersMessages.h" // for TransformData, etc +#include "mozilla/webrender/WebRenderTypes.h" // for RenderRoot +#include "mozilla/TimeStamp.h" // for TimeStamp +#include "mozilla/TimingParams.h" +#include "mozilla/Types.h" // for SideBits +#include "X11UndefineNone.h" +#include <unordered_map> + +namespace mozilla::layers { +class Animation; +class APZSampler; +class CompositorAnimationStorage; +struct AnimatedValue; + +typedef nsTArray<layers::Animation> AnimationArray; + +/** + * This utility class allows reusing code between the webrender and + * non-webrender compositor-side implementations. It provides + * utility functions for sampling animations at particular timestamps. + */ +class AnimationHelper { + public: + struct SampleResult { + enum class Type : uint8_t { None, Skipped, Sampled }; + enum class Reason : uint8_t { None, ScrollToDelayPhase }; + Type mType = Type::None; + Reason mReason = Reason::None; + + SampleResult() = default; + SampleResult(Type aType, Reason aReason) : mType(aType), mReason(aReason) {} + + static SampleResult Skipped() { return {Type::Skipped, Reason::None}; } + static SampleResult Sampled() { return {Type::Sampled, Reason::None}; } + + bool IsNone() { return mType == Type::None; } + bool IsSkipped() { return mType == Type::Skipped; } + bool IsSampled() { return mType == Type::Sampled; } + }; + + /** + * Sample animations based on a given time stamp for a element(layer) with + * its animation data. + * Generally |aPreviousFrameTime| is used for the sampling if it's + * supplied to make the animation more in sync with other animations on the + * main-thread. But in the case where the animation just started at the time + * when the animation was sent to the compositor, |aCurrentFrameTime| is used + * for sampling instead to avoid flicker. + * + * Returns SampleResult::None if none of the animations are producing a result + * (e.g. they are in the delay phase with no backwards fill), + * SampleResult::Skipped if the animation output did not change since the last + * call of this function, + * SampleResult::Sampled if the animation output was updated. + * + * The only exception is the scroll-driven animation. When the user move the + * scrollbar to make the animations go from active phase to delay phase, this + * returns SampleResult::None but sets its |mReason| to + * Reason::ScrollToDelayPhase. The caller can check this flag so we can store + * the base style into the hash table to make sure we have the correct + * rendering result. The base style stays in the hash table until we sync with + * main thread. + * + * Using the same example from ExtractAnimations (below): + * + * Input |aPropertyAnimationGroups| (ignoring the base animation style): + * + * [ + * Group A: [ { rotate, Animation A }, { rotate, Animation B } ], + * Group B: [ { scale, Animation B } ], + * Group C: [ { transform, Animation A }, { transform, Animation B } ], + * ] + * + * For each property group, this function interpolates each animation in turn, + * using the result of interpolating one animation as input for the next such + * that it reduces each property group to a single output value: + * + * [ + * { rotate, StyleAnimationValue }, + * { scale, StyleAnimationValue }, + * { transform, StyleAnimationValue }, + * ] + * + * For transform animations, the caller (SampleAnimations) will combine the + * result of the various transform properties into a final matrix. + */ + static SampleResult SampleAnimationForEachNode( + const APZSampler* aAPZSampler, const LayersId& aLayersId, + const MutexAutoLock& aProofOfMapLock, TimeStamp aPreviousFrameTime, + TimeStamp aCurrentFrameTime, const AnimatedValue* aPreviousValue, + nsTArray<PropertyAnimationGroup>& aPropertyAnimationGroups, + nsTArray<RefPtr<StyleAnimationValue>>& aAnimationValues); + + /** + * Extract organized animation data by property into an array of + * PropertyAnimationGroup objects. + * + * For example, suppose we have the following animations: + * + * Animation A: [ transform, rotate ] + * Animation B: [ rotate, scale ] + * Animation C: [ transform ] + * Animation D: [ opacity ] + * + * When we go to send transform-like properties to the compositor, we + * sort them as follows: + * + * [ + * { rotate: Animation A (rotate segments only) }, + * { rotate: Animation B ( " " ) }, + * { scale: Animation B (scale segments only) }, + * { transform: Animation A (transform segments only) }, + * { transform: Animation C ( " " ) }, + * ] + * + * In this function, we group these animations together by property producing + * output such as the following: + * + * [ + * [ { rotate, Animation A }, { rotate, Animation B } ], + * [ { scale, Animation B } ], + * [ { transform, Animation A }, { transform, Animation B } ], + * ] + * + * In the process of grouping these animations, we also convert their values + * from the rather compact representation we use for transferring across the + * IPC boundary into something we can readily use for sampling. + * + * Note: the animation groups: + * 1. transform-like properties: transfrom, translate, rotate, scale, + * offset-*. + * 2. opacity property: opacity. + * 3. background color property: background-color. + */ + static AnimationStorageData ExtractAnimations( + const LayersId& aLayersId, const AnimationArray& aAnimations); + + /** + * Get a unique id to represent the compositor animation between child + * and parent side. This id will be used as a key to store animation + * data in the CompositorAnimationStorage per compositor. + * Each layer on the content side calls this when it gets new animation + * data. + */ + static uint64_t GetNextCompositorAnimationsId(); + + /** + * Convert an array of animation values into a matrix given the corresponding + * transform parameters. |aValue| must be a transform-like value + * (e.g. transform, translate etc.). + */ + static gfx::Matrix4x4 ServoAnimationValueToMatrix4x4( + const nsTArray<RefPtr<StyleAnimationValue>>& aValue, + const TransformData& aTransformData, gfx::Path* aCachedMotionPath); + + /** + * Returns true if |aPrerenderedRect| transformed by |aTransform| were + * composited in |aClipRect| there appears area which wasn't pre-rendered + * on the main-thread. I.e. checkerboarding. + */ + static bool ShouldBeJank(const LayoutDeviceRect& aPrerenderedRect, + SideBits aOverflowedSides, + const gfx::Matrix4x4& aTransform, + const ParentLayerRect& aClipRect); +}; + +} // namespace mozilla::layers + +#endif // mozilla_layers_AnimationHelper_h |