summaryrefslogtreecommitdiffstats
path: root/gfx/layers/AnimationHelper.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
commit9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /gfx/layers/AnimationHelper.h
parentInitial commit. (diff)
downloadthunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.tar.xz
thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/AnimationHelper.h')
-rw-r--r--gfx/layers/AnimationHelper.h180
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