1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #pragma once
9 
10 #include <ABI49_0_0ReactCommon/ABI49_0_0RuntimeExecutor.h>
11 #include <ABI49_0_0butter/ABI49_0_0set.h>
12 #include <ABI49_0_0React/renderer/animations/ABI49_0_0LayoutAnimationCallbackWrapper.h>
13 #include <ABI49_0_0React/renderer/animations/ABI49_0_0primitives.h>
14 #include <ABI49_0_0React/renderer/core/ABI49_0_0RawValue.h>
15 #include <ABI49_0_0React/renderer/debug/ABI49_0_0flags.h>
16 #include <ABI49_0_0React/renderer/mounting/ABI49_0_0MountingOverrideDelegate.h>
17 #include <ABI49_0_0React/renderer/mounting/ABI49_0_0MountingTransaction.h>
18 #include <ABI49_0_0React/renderer/mounting/ABI49_0_0ShadowViewMutation.h>
19 #include <ABI49_0_0React/renderer/uimanager/ABI49_0_0LayoutAnimationStatusDelegate.h>
20 #include <ABI49_0_0React/renderer/uimanager/ABI49_0_0UIManagerAnimationDelegate.h>
21 
22 #include <optional>
23 
24 namespace ABI49_0_0facebook {
25 namespace ABI49_0_0React {
26 
27 #ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
28 void PrintMutationInstruction(
29     std::string message,
30     ShadowViewMutation const &mutation);
31 void PrintMutationInstructionRelative(
32     std::string message,
33     ShadowViewMutation const &mutation,
34     ShadowViewMutation const &relativeMutation);
35 #else
36 #define PrintMutationInstruction(a, b)
37 #define PrintMutationInstructionRelative(a, b, c)
38 #endif
39 
40 class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
41                                        public MountingOverrideDelegate {
42  public:
43   LayoutAnimationKeyFrameManager(
44       RuntimeExecutor runtimeExecutor,
45       ContextContainer::Shared &contextContainer,
46       LayoutAnimationStatusDelegate *delegate);
47 
48 #pragma mark - UIManagerAnimationDelegate methods
49 
50   void uiManagerDidConfigureNextLayoutAnimation(
51       jsi::Runtime &runtime,
52       RawValue const &config,
53       const jsi::Value &successCallbackValue,
54       const jsi::Value &failureCallbackValue) const override;
55 
56   void setComponentDescriptorRegistry(SharedComponentDescriptorRegistry const &
57                                           componentDescriptorRegistry) override;
58 
59   void setReduceDeleteCreateMutation(bool reduceDeleteCreateMutation) override;
60 
61   // TODO: add SurfaceId to this API as well
62   bool shouldAnimateFrame() const override;
63 
64   void stopSurface(SurfaceId surfaceId) override;
65 
66 #pragma mark - MountingOverrideDelegate methods
67 
68   bool shouldOverridePullTransaction() const override;
69 
70   // This is used to "hijack" the diffing process to figure out which mutations
71   // should be animated. The mutations returned by this function will be
72   // executed immediately.
73   std::optional<MountingTransaction> pullTransaction(
74       SurfaceId surfaceId,
75       MountingTransaction::Number number,
76       TransactionTelemetry const &telemetry,
77       ShadowViewMutationList mutations) const override;
78 
79   // Exposed for testing.
80   void uiManagerDidConfigureNextLayoutAnimation(
81       LayoutAnimation layoutAnimation) const;
82 
83   // LayoutAnimationStatusDelegate - this is for the platform to get
84   // signal when animations start and complete. Setting and resetting this
85   // delegate is protected by a mutex; ALL method calls into this delegate are
86   // also protected by the mutex! The only way to set this without a mutex is
87   // via a constructor.
88   void setLayoutAnimationStatusDelegate(
89       LayoutAnimationStatusDelegate *delegate) const;
90 
91   void setClockNow(std::function<uint64_t()> now);
92 
93  protected:
94   SharedComponentDescriptorRegistry componentDescriptorRegistry_;
95   mutable std::optional<LayoutAnimation> currentAnimation_{};
96   mutable std::mutex currentAnimationMutex_;
97 
98   /**
99    * All mutations of inflightAnimations_ are thread-safe as long as
100    * we keep the contract of: only mutate it within the context of
101    * `pullTransaction`. If that contract is held, this is implicitly protected
102    * by the MountingCoordinator's mutex.
103    */
104   mutable std::vector<LayoutAnimation> inflightAnimations_{};
105 
106   bool hasComponentDescriptorForShadowView(ShadowView const &shadowView) const;
107   ComponentDescriptor const &getComponentDescriptorForShadowView(
108       ShadowView const &shadowView) const;
109 
110   /**
111    * Given a `progress` between 0 and 1, a mutation and LayoutAnimation config,
112    * return a ShadowView with mutated props and/or LayoutMetrics.
113    *
114    * @param progress
115    * @param layoutAnimation
116    * @param animatedMutation
117    * @return
118    */
119   ShadowView createInterpolatedShadowView(
120       Float progress,
121       ShadowView const &startingView,
122       ShadowView const &finalView) const;
123 
124   void callCallback(const LayoutAnimationCallbackWrapper &callback) const;
125 
126   virtual void animationMutationsForFrame(
127       SurfaceId surfaceId,
128       ShadowViewMutation::List &mutationsList,
129       uint64_t now) const = 0;
130 
131   /**
132    * Queue (and potentially synthesize) final mutations for a finished keyframe.
133    * Keyframe animation may have timed-out, or be canceled due to a conflict.
134    */
135   void queueFinalMutationsForCompletedKeyFrame(
136       AnimationKeyFrame const &keyframe,
137       ShadowViewMutation::List &mutationsList,
138       bool interrupted,
139       const std::string &logPrefix) const;
140 
141  private:
142   RuntimeExecutor runtimeExecutor_;
143   ContextContainer::Shared contextContainer_;
144 
145   mutable std::mutex layoutAnimationStatusDelegateMutex_;
146   mutable LayoutAnimationStatusDelegate *layoutAnimationStatusDelegate_{};
147   mutable std::mutex surfaceIdsToStopMutex_;
148   mutable butter::set<SurfaceId> surfaceIdsToStop_{};
149   bool reduceDeleteCreateMutation_{false};
150 
151   // Function that returns current time in milliseconds
152   std::function<uint64_t()> now_;
153 
154   void adjustImmediateMutationIndicesForDelayedMutations(
155       SurfaceId surfaceId,
156       ShadowViewMutation &mutation,
157       bool skipLastAnimation = false,
158       bool lastAnimationOnly = false) const;
159 
160   void adjustDelayedMutationIndicesForMutation(
161       SurfaceId surfaceId,
162       ShadowViewMutation const &mutation,
163       bool skipLastAnimation = false) const;
164 
165   void getAndEraseConflictingAnimations(
166       SurfaceId surfaceId,
167       ShadowViewMutationList const &mutations,
168       std::vector<AnimationKeyFrame> &conflictingAnimations) const;
169 
170   /*
171    * Removes animations from `inflightAnimations_` for stopped surfaces.
172    */
173   void deleteAnimationsForStoppedSurfaces() const;
174 
175   void simulateImagePropsMemoryAccess(
176       ShadowViewMutationList const &mutations) const;
177 };
178 
179 } // namespace ABI49_0_0React
180 } // namespace ABI49_0_0facebook
181