/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace facebook::react { #ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING void PrintMutationInstruction( std::string message, const ShadowViewMutation& mutation); void PrintMutationInstructionRelative( std::string message, const ShadowViewMutation& mutation, const ShadowViewMutation& relativeMutation); #else #define PrintMutationInstruction(a, b) #define PrintMutationInstructionRelative(a, b, c) #endif class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate, public MountingOverrideDelegate { public: LayoutAnimationKeyFrameManager( RuntimeExecutor runtimeExecutor, ContextContainer::Shared& contextContainer, LayoutAnimationStatusDelegate* delegate); #pragma mark - UIManagerAnimationDelegate methods void uiManagerDidConfigureNextLayoutAnimation( jsi::Runtime& runtime, const RawValue& config, const jsi::Value& successCallbackValue, const jsi::Value& failureCallbackValue) const override; void setComponentDescriptorRegistry(const SharedComponentDescriptorRegistry& componentDescriptorRegistry) override; void setReduceDeleteCreateMutation(bool reduceDeleteCreateMutation) override; // TODO: add SurfaceId to this API as well bool shouldAnimateFrame() const override; void stopSurface(SurfaceId surfaceId) override; #pragma mark - MountingOverrideDelegate methods bool shouldOverridePullTransaction() const override; // This is used to "hijack" the diffing process to figure out which mutations // should be animated. The mutations returned by this function will be // executed immediately. std::optional pullTransaction( SurfaceId surfaceId, MountingTransaction::Number number, const TransactionTelemetry& telemetry, ShadowViewMutationList mutations) const override; // Exposed for testing. void uiManagerDidConfigureNextLayoutAnimation( LayoutAnimation layoutAnimation) const; // LayoutAnimationStatusDelegate - this is for the platform to get // signal when animations start and complete. Setting and resetting this // delegate is protected by a mutex; ALL method calls into this delegate are // also protected by the mutex! The only way to set this without a mutex is // via a constructor. void setLayoutAnimationStatusDelegate( LayoutAnimationStatusDelegate* delegate) const; void setClockNow(std::function now); protected: SharedComponentDescriptorRegistry componentDescriptorRegistry_; mutable std::optional currentAnimation_{}; mutable std::mutex currentAnimationMutex_; /** * All mutations of inflightAnimations_ are thread-safe as long as * we keep the contract of: only mutate it within the context of * `pullTransaction`. If that contract is held, this is implicitly protected * by the MountingCoordinator's mutex. */ mutable std::vector inflightAnimations_{}; bool hasComponentDescriptorForShadowView(const ShadowView& shadowView) const; const ComponentDescriptor& getComponentDescriptorForShadowView( const ShadowView& shadowView) const; /** * Given a `progress` between 0 and 1, a mutation and LayoutAnimation config, * return a ShadowView with mutated props and/or LayoutMetrics. * * @param progress * @param layoutAnimation * @param animatedMutation * @return */ ShadowView createInterpolatedShadowView( Float progress, const ShadowView& startingView, const ShadowView& finalView) const; void callCallback(const LayoutAnimationCallbackWrapper& callback) const; virtual void animationMutationsForFrame( SurfaceId surfaceId, ShadowViewMutation::List& mutationsList, uint64_t now) const = 0; /** * Queue (and potentially synthesize) final mutations for a finished keyframe. * Keyframe animation may have timed-out, or be canceled due to a conflict. */ void queueFinalMutationsForCompletedKeyFrame( const AnimationKeyFrame& keyframe, ShadowViewMutation::List& mutationsList, bool interrupted, const std::string& logPrefix) const; private: RuntimeExecutor runtimeExecutor_; ContextContainer::Shared contextContainer_; mutable std::mutex layoutAnimationStatusDelegateMutex_; mutable LayoutAnimationStatusDelegate* layoutAnimationStatusDelegate_{}; mutable std::mutex surfaceIdsToStopMutex_; mutable std::unordered_set surfaceIdsToStop_{}; bool reduceDeleteCreateMutation_{false}; // Function that returns current time in milliseconds std::function now_; void adjustImmediateMutationIndicesForDelayedMutations( SurfaceId surfaceId, ShadowViewMutation& mutation, bool skipLastAnimation = false, bool lastAnimationOnly = false) const; void adjustDelayedMutationIndicesForMutation( SurfaceId surfaceId, const ShadowViewMutation& mutation, bool skipLastAnimation = false) const; void getAndEraseConflictingAnimations( SurfaceId surfaceId, const ShadowViewMutationList& mutations, std::vector& conflictingAnimations) const; /* * Removes animations from `inflightAnimations_` for stopped surfaces. */ void deleteAnimationsForStoppedSurfaces() const; void simulateImagePropsMemoryAccess( const ShadowViewMutationList& mutations) const; /** * Interpolates the props values. */ Props::Shared interpolateProps( const ComponentDescriptor& componentDescriptor, const PropsParserContext& context, Float animationProgress, const Props::Shared& props, const Props::Shared& newProps) const; }; } // namespace facebook::react