diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 8c876c379f..25821a72e6 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -70,7 +70,7 @@ class SchedulerDelegateProxy : public SchedulerDelegate { { if (self = [super init]) { _delegateProxy = std::make_shared((__bridge void *)self); - _scheduler = std::make_shared(toolbox, nullptr, _delegateProxy.get()); + _scheduler = std::make_shared(toolbox, _delegateProxy.get()); } return self; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 54830fe1ac..95ea4b0e50 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -288,7 +288,7 @@ void Binding::installFabricUIManager( toolbox.runtimeExecutor = runtimeExecutor; toolbox.synchronousEventBeatFactory = synchronousBeatFactory; toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory; - scheduler_ = std::make_shared(toolbox, nullptr, this); + scheduler_ = std::make_shared(toolbox, this); } void Binding::uninstallFabricUIManager() { diff --git a/ReactCommon/fabric/animations/BUCK b/ReactCommon/fabric/animations/BUCK deleted file mode 100644 index fde3bc7dec..0000000000 --- a/ReactCommon/fabric/animations/BUCK +++ /dev/null @@ -1,95 +0,0 @@ -load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_preprocessor_flags_for_build_mode") -load( - "//tools/build_defs/oss:rn_defs.bzl", - "ANDROID", - "APPLE", - "CXX", - "fb_xplat_cxx_test", - "get_apple_compiler_flags", - "get_apple_inspector_flags", - "react_native_xplat_target", - "rn_xplat_cxx_library", - "subdir_glob", -) - -APPLE_COMPILER_FLAGS = get_apple_compiler_flags() - -rn_xplat_cxx_library( - name = "animations", - srcs = glob( - ["**/*.cpp"], - exclude = glob(["tests/**/*.cpp"]), - ), - headers = glob( - ["**/*.h"], - exclude = glob(["tests/**/*.h"]), - ), - header_namespace = "", - exported_headers = subdir_glob( - [ - ("", "*.h"), - ], - prefix = "react/animations", - ), - compiler_flags = [ - "-fexceptions", - "-frtti", - "-std=c++14", - "-Wall", - ], - fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(), - force_static = True, - labels = ["supermodule:xplat/default/public.react_native.infra"], - macosx_tests_override = [], - platforms = (ANDROID, APPLE, CXX), - preprocessor_flags = [ - "-DLOG_TAG=\"ReactNative\"", - "-DWITH_FBSYSTRACE=1", - ], - tests = [":tests"], - visibility = ["PUBLIC"], - deps = [ - "//third-party/glog:glog", - "//xplat/fbsystrace:fbsystrace", - "//xplat/folly:headers_only", - "//xplat/folly:memory", - "//xplat/folly:molly", - "//xplat/jsi:JSIDynamic", - "//xplat/jsi:jsi", - react_native_xplat_target("config:config"), - react_native_xplat_target("fabric/componentregistry:componentregistry"), - react_native_xplat_target("fabric/components/view:view"), - react_native_xplat_target("fabric/core:core"), - react_native_xplat_target("fabric/debug:debug"), - react_native_xplat_target("fabric/mounting:mounting"), - react_native_xplat_target("fabric/uimanager:uimanager"), - react_native_xplat_target("runtimeexecutor:runtimeexecutor"), - ], -) - -fb_xplat_cxx_test( - name = "tests", - srcs = glob(["tests/**/*.cpp"]), - headers = glob(["tests/**/*.h"]), - compiler_flags = [ - "-fexceptions", - "-frtti", - "-std=c++14", - "-Wall", - ], - contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE, CXX), - deps = [ - ":animations", - "//xplat/folly:molly", - "//xplat/third-party/gmock:gtest", - react_native_xplat_target("config:config"), - react_native_xplat_target("fabric/components/activityindicator:activityindicator"), - react_native_xplat_target("fabric/components/image:image"), - react_native_xplat_target("fabric/components/root:root"), - react_native_xplat_target("fabric/components/scrollview:scrollview"), - react_native_xplat_target("fabric/components/view:view"), - "//xplat/js/react-native-github:generated_components-rncore", - ], -) diff --git a/ReactCommon/fabric/animations/LayoutAnimationDriver.cpp b/ReactCommon/fabric/animations/LayoutAnimationDriver.cpp deleted file mode 100644 index a1e1da9564..0000000000 --- a/ReactCommon/fabric/animations/LayoutAnimationDriver.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "LayoutAnimationDriver.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -namespace facebook { -namespace react { - -static double -getProgressFromValues(double start, double end, double currentValue) { - auto opacityMinmax = std::minmax({start, end}); - auto min = opacityMinmax.first; - auto max = opacityMinmax.second; - return ( - currentValue < min - ? 0 - : (currentValue > max ? 0 : ((max - currentValue) / (max - min)))); -} - -/** - * Given an animation and a ShadowView with properties set on it, detect how - * far through the animation the ShadowView has progressed. - * - * @param mutationsList - * @param now - */ -double LayoutAnimationDriver::getProgressThroughAnimation( - AnimationKeyFrame const &keyFrame, - LayoutAnimation const *layoutAnimation, - ShadowView const &animationStateView) const { - auto layoutAnimationConfig = layoutAnimation->layoutAnimationConfig; - auto const mutationConfig = - *(keyFrame.type == AnimationConfigurationType::Delete - ? layoutAnimationConfig.deleteConfig - : (keyFrame.type == AnimationConfigurationType::Create - ? layoutAnimationConfig.createConfig - : layoutAnimationConfig.updateConfig)); - - auto initialProps = keyFrame.viewStart.props; - auto finalProps = keyFrame.viewEnd.props; - - if (mutationConfig.animationProperty == AnimationProperty::Opacity) { - // Detect progress through opacity animation. - const auto &oldViewProps = - dynamic_cast(initialProps.get()); - const auto &newViewProps = - dynamic_cast(finalProps.get()); - const auto &animationStateViewProps = - dynamic_cast(animationStateView.props.get()); - if (oldViewProps != nullptr && newViewProps != nullptr && - animationStateViewProps != nullptr) { - return getProgressFromValues( - oldViewProps->opacity, - newViewProps->opacity, - animationStateViewProps->opacity); - } - } else if ( - mutationConfig.animationProperty != AnimationProperty::NotApplicable) { - // Detect progress through layout animation. - LayoutMetrics const &finalLayoutMetrics = keyFrame.viewEnd.layoutMetrics; - LayoutMetrics const &baselineLayoutMetrics = - keyFrame.viewStart.layoutMetrics; - LayoutMetrics const &animationStateLayoutMetrics = - animationStateView.layoutMetrics; - - if (baselineLayoutMetrics.frame.size.height != - finalLayoutMetrics.frame.size.height) { - return getProgressFromValues( - baselineLayoutMetrics.frame.size.height, - finalLayoutMetrics.frame.size.height, - animationStateLayoutMetrics.frame.size.height); - } - if (baselineLayoutMetrics.frame.size.width != - finalLayoutMetrics.frame.size.width) { - return getProgressFromValues( - baselineLayoutMetrics.frame.size.width, - finalLayoutMetrics.frame.size.width, - animationStateLayoutMetrics.frame.size.width); - } - if (baselineLayoutMetrics.frame.origin.x != - finalLayoutMetrics.frame.origin.x) { - return getProgressFromValues( - baselineLayoutMetrics.frame.origin.x, - finalLayoutMetrics.frame.origin.x, - animationStateLayoutMetrics.frame.origin.x); - } - if (baselineLayoutMetrics.frame.origin.y != - finalLayoutMetrics.frame.origin.y) { - return getProgressFromValues( - baselineLayoutMetrics.frame.origin.y, - finalLayoutMetrics.frame.origin.y, - animationStateLayoutMetrics.frame.origin.y); - } - } - - return 0; -} - -void LayoutAnimationDriver::animationMutationsForFrame( - SurfaceId surfaceId, - ShadowViewMutation::List &mutationsList, - uint64_t now) const { - for (auto &animation : inflightAnimations_) { - if (animation.surfaceId != surfaceId) { - continue; - } - - int incompleteAnimations = 0; - for (const auto &keyframe : animation.keyFrames) { - if (keyframe.type == AnimationConfigurationType::Noop) { - continue; - } - - auto const &baselineShadowView = keyframe.viewStart; - auto const &finalShadowView = keyframe.viewEnd; - - // The contract with the "keyframes generation" phase is that any animated - // node will have a valid configuration. - auto const layoutAnimationConfig = animation.layoutAnimationConfig; - auto const mutationConfig = - (keyframe.type == AnimationConfigurationType::Delete - ? layoutAnimationConfig.deleteConfig - : (keyframe.type == AnimationConfigurationType::Create - ? layoutAnimationConfig.createConfig - : layoutAnimationConfig.updateConfig)); - - // Interpolate - std::pair progress = - calculateAnimationProgress(now, animation, *mutationConfig); - double animationTimeProgressLinear = progress.first; - double animationInterpolationFactor = progress.second; - - auto mutatedShadowView = createInterpolatedShadowView( - animationInterpolationFactor, - *mutationConfig, - baselineShadowView, - finalShadowView); - - // Create the mutation instruction - mutationsList.push_back(ShadowViewMutation::UpdateMutation( - keyframe.parentView, baselineShadowView, mutatedShadowView, -1)); - - if (animationTimeProgressLinear < 1) { - incompleteAnimations++; - } - } - - // Are there no ongoing mutations left in this animation? - if (incompleteAnimations == 0) { - animation.completed = true; - } - } - - // Clear out finished animations - for (auto it = inflightAnimations_.begin(); - it != inflightAnimations_.end();) { - const auto &animation = *it; - if (animation.completed) { - // Queue up "final" mutations for all keyframes in the completed animation - for (auto const &keyframe : animation.keyFrames) { - if (keyframe.finalMutationForKeyFrame.hasValue()) { - mutationsList.push_back(*keyframe.finalMutationForKeyFrame); - } - } - - it = inflightAnimations_.erase(it); - } else { - it++; - } - } -} - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/animations/LayoutAnimationDriver.h b/ReactCommon/fabric/animations/LayoutAnimationDriver.h deleted file mode 100644 index 2a22157752..0000000000 --- a/ReactCommon/fabric/animations/LayoutAnimationDriver.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its 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 "LayoutAnimationKeyFrameManager.h" - -namespace facebook { -namespace react { - -class LayoutAnimationDriver : public LayoutAnimationKeyFrameManager { - public: - virtual ~LayoutAnimationDriver() {} - - protected: - virtual void animationMutationsForFrame( - SurfaceId surfaceId, - ShadowViewMutation::List &mutationsList, - uint64_t now) const override; - virtual double getProgressThroughAnimation( - AnimationKeyFrame const &keyFrame, - LayoutAnimation const *layoutAnimation, - ShadowView const &animationStateView) const override; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/animations/LayoutAnimationKeyFrameManager.cpp b/ReactCommon/fabric/animations/LayoutAnimationKeyFrameManager.cpp deleted file mode 100644 index 4f617bf71f..0000000000 --- a/ReactCommon/fabric/animations/LayoutAnimationKeyFrameManager.cpp +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "LayoutAnimationKeyFrameManager.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -namespace facebook { -namespace react { - -static better::optional parseAnimationType(std::string param) { - if (param == "spring") { - return better::optional(AnimationType::Spring); - } - if (param == "linear") { - return better::optional(AnimationType::Linear); - } - if (param == "easeInEaseOut") { - return better::optional(AnimationType::EaseInEaseOut); - } - if (param == "easeIn") { - return better::optional(AnimationType::EaseIn); - } - if (param == "easeOut") { - return better::optional(AnimationType::EaseOut); - } - if (param == "keyboard") { - return better::optional(AnimationType::Keyboard); - } - - return {}; -} - -static better::optional parseAnimationProperty( - std::string param) { - if (param == "opacity") { - return better::optional(AnimationProperty::Opacity); - } - if (param == "scaleX") { - return better::optional(AnimationProperty::ScaleX); - } - if (param == "scaleY") { - return better::optional(AnimationProperty::ScaleY); - } - if (param == "scaleXY") { - return better::optional(AnimationProperty::ScaleXY); - } - - return {}; -} - -static better::optional parseAnimationConfig( - folly::dynamic const &config, - double defaultDuration) { - if (config.empty() || !config.isObject()) { - return better::optional( - AnimationConfig{AnimationType::Linear, - AnimationProperty::NotApplicable, - defaultDuration, - 0, - 0, - 0}); - } - - folly::dynamic const &animationTypeParam = config["type"]; - if (animationTypeParam.empty() || !animationTypeParam.isString()) { - return {}; - } - const auto animationType = parseAnimationType(animationTypeParam.asString()); - if (!animationType) { - return {}; - } - - folly::dynamic const &animationPropertyParam = config["property"]; - if (animationPropertyParam.empty() || !animationPropertyParam.isString()) { - return {}; - } - const auto animationProperty = - parseAnimationProperty(animationPropertyParam.asString()); - if (!animationProperty) { - return {}; - } - - double duration = defaultDuration; - double delay = 0; - double springDamping = 0; - double initialVelocity = 0; - - auto const durationIt = config.find("duration"); - if (durationIt != config.items().end()) { - if (durationIt->second.isDouble()) { - duration = durationIt->second.asDouble(); - } else { - return {}; - } - } - - auto const delayIt = config.find("delay"); - if (delayIt != config.items().end()) { - if (delayIt->second.isDouble()) { - delay = delayIt->second.asDouble(); - } else { - return {}; - } - } - - auto const springDampingIt = config.find("springDamping"); - if (springDampingIt != config.items().end() && - springDampingIt->second.isDouble()) { - if (springDampingIt->second.isDouble()) { - springDamping = springDampingIt->second.asDouble(); - } else { - return {}; - } - } - - auto const initialVelocityIt = config.find("initialVelocity"); - if (initialVelocityIt != config.items().end()) { - if (initialVelocityIt->second.isDouble()) { - initialVelocity = initialVelocityIt->second.asDouble(); - } else { - return {}; - } - } - - return better::optional(AnimationConfig{*animationType, - *animationProperty, - duration, - delay, - springDamping, - initialVelocity}); -} - -// Parse animation config from JS -static better::optional parseLayoutAnimationConfig( - folly::dynamic const &config) { - if (config.empty() || !config.isObject()) { - return {}; - } - - auto const durationIt = config.find("duration"); - if (durationIt == config.items().end() || !durationIt->second.isDouble()) { - return {}; - } - const double duration = durationIt->second.asDouble(); - - const auto createConfig = parseAnimationConfig(config["create"], duration); - if (!createConfig) { - return {}; - } - - const auto updateConfig = parseAnimationConfig(config["update"], duration); - if (!updateConfig) { - return {}; - } - - const auto deleteConfig = parseAnimationConfig(config["delete"], duration); - if (!deleteConfig) { - return {}; - } - - return better::optional(LayoutAnimationConfig{ - duration, *createConfig, *updateConfig, *deleteConfig}); -} - -/** - * Globally configure next LayoutAnimation. - */ -void LayoutAnimationKeyFrameManager::uiManagerDidConfigureNextLayoutAnimation( - RawValue const &config, - std::shared_ptr successCallback, - std::shared_ptr errorCallback) const { - auto layoutAnimationConfig = - parseLayoutAnimationConfig((folly::dynamic)config); - - if (layoutAnimationConfig) { - std::lock_guard lock(currentAnimationMutex_); - currentAnimation_ = better::optional{ - LayoutAnimation{-1, - 0, - false, - *layoutAnimationConfig, - successCallback, - errorCallback, - {}}}; - } else { - // TODO: call errorCallback - LOG(ERROR) << "Parsing LayoutAnimationConfig failed: " - << (folly::dynamic)config; - } -} - -bool LayoutAnimationKeyFrameManager::shouldOverridePullTransaction() const { - return shouldAnimateFrame(); -} - -bool LayoutAnimationKeyFrameManager::shouldAnimateFrame() const { - // There is potentially a race here between getting and setting - // `currentMutation_`. We don't want to lock around this because then we're - // creating contention between pullTransaction and the JS thread. - return currentAnimation_ || !inflightAnimations_.empty(); -} - -static inline const float -interpolateFloats(float coefficient, float oldValue, float newValue) { - return oldValue + (newValue - oldValue) * coefficient; -} - -std::pair -LayoutAnimationKeyFrameManager::calculateAnimationProgress( - uint64_t now, - const LayoutAnimation &animation, - const AnimationConfig &mutationConfig) const { - uint64_t startTime = animation.startTime; - uint64_t delay = mutationConfig.delay; - uint64_t endTime = startTime + delay + mutationConfig.duration; - double progress = (now >= endTime) - ? 1 - : ((now < startTime + delay) ? 0 - : 1 - - (double)(endTime - delay - now) / - (double)(endTime - animation.startTime)); - return {progress, progress}; -} - -void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation( - SurfaceId surfaceId, - ShadowViewMutation const &mutation) const { - bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove; - bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert; - assert(isRemoveMutation || isInsertMutation); - - for (auto &inflightAnimation : inflightAnimations_) { - if (inflightAnimation.surfaceId != surfaceId) { - continue; - } - - for (auto it = inflightAnimation.keyFrames.begin(); - it != inflightAnimation.keyFrames.end(); - it++) { - auto &animatedKeyFrame = *it; - - // Detect if they're in the same view hierarchy, but not equivalent - // (We've already detected direct conflicts and handled them above) - if (animatedKeyFrame.parentView.tag != mutation.parentShadowView.tag) { - continue; - } - - if (animatedKeyFrame.type != AnimationConfigurationType::Noop) { - continue; - } - if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) { - continue; - } - ShadowViewMutation &finalAnimationMutation = - *animatedKeyFrame.finalMutationForKeyFrame; - - if (finalAnimationMutation.type != ShadowViewMutation::Type::Remove) { - continue; - } - - // Do we need to adjust the index of this operation? - if (isRemoveMutation && mutation.index <= finalAnimationMutation.index) { - finalAnimationMutation.index--; - } else if ( - isInsertMutation && mutation.index <= finalAnimationMutation.index) { - finalAnimationMutation.index++; - } - } - } -} - -better::optional -LayoutAnimationKeyFrameManager::pullTransaction( - SurfaceId surfaceId, - MountingTransaction::Number transactionNumber, - MountingTelemetry const &telemetry, - ShadowViewMutationList mutations) const { - // Current time in milliseconds - uint64_t now = - std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); - - if (!mutations.empty()) { -#ifdef RN_SHADOW_TREE_INTROSPECTION - { - std::stringstream ss(getDebugDescription(mutations, {})); - std::string to; - while (std::getline(ss, to, '\n')) { - LOG(ERROR) - << "LayoutAnimationKeyFrameManager.cpp: got mutation list: Line: " - << to; - } - }; -#endif - - // What to do if we detect a conflict? Get current value and make - // that the baseline of the next animation. Scale the remaining time - // in the animation - // Types of conflicts and how we handle them: - // Update -> update: remove the previous update, make it the baseline of the - // next update (with current progress) Update -> remove: same, with final - // mutation being a remove Insert -> update: treat as update->update Insert - // -> remove: same, as update->remove Remove -> update/insert: not possible - // We just collect pairs here of and delete them - // from active animations. If another animation is queued up from the - // current mutations then these deleted mutations will serve as the baseline - // for the next animation. If not, the current mutations are executed - // immediately without issues. - std::vector< - std::tuple> - conflictingAnimations{}; - for (auto &mutation : mutations) { - auto const &baselineShadowView = - (mutation.type == ShadowViewMutation::Type::Insert) - ? mutation.newChildShadowView - : mutation.oldChildShadowView; - - for (auto &inflightAnimation : inflightAnimations_) { - if (inflightAnimation.surfaceId != surfaceId) { - continue; - } - - for (auto it = inflightAnimation.keyFrames.begin(); - it != inflightAnimation.keyFrames.end();) { - auto &animatedKeyFrame = *it; - - // Conflicting animation detected - if (animatedKeyFrame.tag == baselineShadowView.tag) { - auto const layoutAnimationConfig = - inflightAnimation.layoutAnimationConfig; - - auto const mutationConfig = - (animatedKeyFrame.type == AnimationConfigurationType::Delete - ? layoutAnimationConfig.deleteConfig - : (animatedKeyFrame.type == - AnimationConfigurationType::Create - ? layoutAnimationConfig.createConfig - : layoutAnimationConfig.updateConfig)); - - conflictingAnimations.push_back(std::make_tuple( - animatedKeyFrame, *mutationConfig, &inflightAnimation)); - - // Delete from existing animation - it = inflightAnimation.keyFrames.erase(it); - } else { - it++; - } - } - } - } - - // Are we animating this list of mutations? - better::optional currentAnimation{}; - { - std::lock_guard lock(currentAnimationMutex_); - if (currentAnimation_) { - currentAnimation = currentAnimation_; - currentAnimation_ = {}; - } - } - - if (currentAnimation) { - LayoutAnimation animation = currentAnimation.value(); - animation.surfaceId = surfaceId; - animation.startTime = now; - - // Pre-process list to: - // Catch remove+reinsert (reorders) - // Catch delete+create (reparenting) (this should be optimized away at - // the diffing level eventually?) - // TODO: to prevent this step we could tag Remove/Insert mutations as - // being moves on the Differ level, since we know that there? We could use - // TinyMap here, but it's not exposed by Differentiator (yet). - std::vector insertedTags; - std::vector createdTags; - std::unordered_map movedTags; - std::vector reparentedTags; - for (const auto &mutation : mutations) { - if (mutation.type == ShadowViewMutation::Type::Insert) { - insertedTags.push_back(mutation.newChildShadowView.tag); - } - if (mutation.type == ShadowViewMutation::Type::Create) { - createdTags.push_back(mutation.newChildShadowView.tag); - } - } - - // Process mutations list into operations that can be sent to platform - // immediately, and those that need to be animated Deletions, removals, - // updates are delayed and animated. Creations and insertions are sent to - // platform and then "animated in" with opacity updates. Upon completion, - // removals and deletions are sent to platform - ShadowViewMutation::List immediateMutations; - - // Remove operations that are actually moves should be copied to - // "immediate mutations". The corresponding "insert" will also be executed - // immediately and animated as an update. - std::vector keyFramesToAnimate; - std::vector movesToAnimate; - auto const layoutAnimationConfig = animation.layoutAnimationConfig; - for (auto &mutation : mutations) { - ShadowView baselineShadowView = - (mutation.type == ShadowViewMutation::Type::Delete || - mutation.type == ShadowViewMutation::Type::Remove - ? mutation.oldChildShadowView - : mutation.newChildShadowView); - auto const &componentDescriptor = - getComponentDescriptorForShadowView(baselineShadowView); - - auto mutationConfig = - (mutation.type == ShadowViewMutation::Type::Delete - ? layoutAnimationConfig.deleteConfig - : (mutation.type == ShadowViewMutation::Type::Insert - ? layoutAnimationConfig.createConfig - : layoutAnimationConfig.updateConfig)); - - bool isRemoveReinserted = - mutation.type == ShadowViewMutation::Type::Remove && - std::find( - insertedTags.begin(), - insertedTags.end(), - mutation.oldChildShadowView.tag) != insertedTags.end(); - - // Reparenting can result in a node being removed, inserted (moved) and - // also deleted and created in the same frame, with the same props etc. - // This should eventually be optimized out of the diffing algorithm, but - // for now we detect reparenting and prevent the corresponding - // Delete/Create instructions from being animated. - bool isReparented = - (mutation.type == ShadowViewMutation::Delete && - std::find( - createdTags.begin(), - createdTags.end(), - mutation.oldChildShadowView.tag) != createdTags.end()) || - (mutation.type == ShadowViewMutation::Create && - std::find( - reparentedTags.begin(), - reparentedTags.end(), - mutation.newChildShadowView.tag) != reparentedTags.end()); - - if (isRemoveReinserted) { - movedTags.insert({mutation.oldChildShadowView.tag, mutation}); - } - - if (isReparented && mutation.type == ShadowViewMutation::Delete) { - reparentedTags.push_back(mutation.oldChildShadowView.tag); - } - - // Inserts that follow a "remove" of the same tag should be treated as - // an update (move) animation. - bool wasInsertedTagRemoved = false; - bool haveConfiguration = mutationConfig.has_value(); - if (mutation.type == ShadowViewMutation::Type::Insert) { - // If this is a move, we actually don't want to copy this insert - // instruction to animated instructions - we want to - // generate an Update mutation for Remove+Insert pairs to animate - // the layout. - // The corresponding Remove and Insert instructions will instead - // be treated as "immediate" instructions. - auto movedIt = movedTags.find(mutation.newChildShadowView.tag); - wasInsertedTagRemoved = movedIt != movedTags.end(); - if (wasInsertedTagRemoved) { - mutationConfig = layoutAnimationConfig.updateConfig; - } - haveConfiguration = mutationConfig.has_value(); - - if (wasInsertedTagRemoved && haveConfiguration) { - movesToAnimate.push_back( - AnimationKeyFrame{{}, - AnimationConfigurationType::Update, - mutation.newChildShadowView.tag, - mutation.parentShadowView, - movedIt->second.oldChildShadowView, - mutation.newChildShadowView}); - } - } - - // Creates and inserts should also be executed immediately. - // Mutations that would otherwise be animated, but have no - // configuration, are also executed immediately. - if (isRemoveReinserted || !haveConfiguration || isReparented || - mutation.type == ShadowViewMutation::Type::Create || - mutation.type == ShadowViewMutation::Type::Insert) { - immediateMutations.push_back(mutation); - - // Adjust indices for any non-directly-conflicting animations that - // affect the same parent view by inserting or removing anything - // from the hierarchy. - if (mutation.type == ShadowViewMutation::Type::Insert || - mutation.type == ShadowViewMutation::Type::Remove) { - adjustDelayedMutationIndicesForMutation(surfaceId, mutation); - } - } - - // Deletes, non-move inserts, updates get animated - if (!wasInsertedTagRemoved && !isRemoveReinserted && !isReparented && - haveConfiguration && - mutation.type != ShadowViewMutation::Type::Create) { - ShadowView viewStart = ShadowView( - mutation.type == ShadowViewMutation::Type::Insert - ? mutation.newChildShadowView - : mutation.oldChildShadowView); - ShadowView viewFinal = ShadowView( - mutation.type == ShadowViewMutation::Type::Update - ? mutation.newChildShadowView - : viewStart); - ShadowView parent = mutation.parentShadowView; - Tag tag = viewStart.tag; - Tag parentTag = mutation.parentShadowView.tag; - - AnimationKeyFrame keyFrame{}; - if (mutation.type == ShadowViewMutation::Type::Insert) { - if (mutationConfig->animationProperty == - AnimationProperty::Opacity) { - auto props = componentDescriptor.cloneProps(viewStart.props, {}); - const auto viewProps = - dynamic_cast(props.get()); - if (viewProps != nullptr) { - const_cast(viewProps)->opacity = 0; - } - viewStart.props = props; - } - bool isScaleX = mutationConfig->animationProperty == - AnimationProperty::ScaleX || - mutationConfig->animationProperty == AnimationProperty::ScaleXY; - bool isScaleY = mutationConfig->animationProperty == - AnimationProperty::ScaleY || - mutationConfig->animationProperty == AnimationProperty::ScaleXY; - if (isScaleX || isScaleY) { - auto props = componentDescriptor.cloneProps(viewStart.props, {}); - const auto viewProps = - dynamic_cast(props.get()); - if (viewProps != nullptr) { - const_cast(viewProps)->transform = - Transform::Scale(isScaleX ? 0 : 1, isScaleY ? 0 : 1, 1); - } - viewStart.props = props; - } - - keyFrame = AnimationKeyFrame{{}, - AnimationConfigurationType::Create, - tag, - parent, - viewStart, - viewFinal, - 0}; - } else if (mutation.type == ShadowViewMutation::Type::Delete) { - if (mutationConfig->animationProperty == - AnimationProperty::Opacity) { - auto props = componentDescriptor.cloneProps(viewFinal.props, {}); - const auto viewProps = - dynamic_cast(props.get()); - if (viewProps != nullptr) { - const_cast(viewProps)->opacity = 0; - } - viewFinal.props = props; - } - bool isScaleX = mutationConfig->animationProperty == - AnimationProperty::ScaleX || - mutationConfig->animationProperty == AnimationProperty::ScaleXY; - bool isScaleY = mutationConfig->animationProperty == - AnimationProperty::ScaleY || - mutationConfig->animationProperty == AnimationProperty::ScaleXY; - if (isScaleX || isScaleY) { - auto props = componentDescriptor.cloneProps(viewFinal.props, {}); - const auto viewProps = - dynamic_cast(props.get()); - if (viewProps != nullptr) { - const_cast(viewProps)->transform = - Transform::Scale(isScaleX ? 0 : 1, isScaleY ? 0 : 1, 1); - } - viewFinal.props = props; - } - - keyFrame = AnimationKeyFrame{ - better::optional(mutation), - AnimationConfigurationType::Delete, - tag, - parent, - viewStart, - viewFinal, - 0}; - } else if (mutation.type == ShadowViewMutation::Type::Update) { - viewFinal = ShadowView(mutation.newChildShadowView); - - keyFrame = AnimationKeyFrame{ - better::optional(mutation), - AnimationConfigurationType::Update, - tag, - parent, - viewStart, - viewFinal, - 0}; - } else { - // This should just be "Remove" instructions that are not animated - // (either this is a "move", or there's a corresponding "Delete" - // that is animated). We configure it as a Noop animation so it is - // executed when all the other animations are completed. - assert(mutation.type == ShadowViewMutation::Type::Remove); - - // For remove instructions: since the execution of the Remove - // instruction will be delayed and therefore may execute outside of - // otherwise-expected order, other views may be inserted before the - // Remove is executed, requiring index adjustment. - { - int adjustedIndex = mutation.index; - for (const auto &otherMutation : mutations) { - if (otherMutation.type == ShadowViewMutation::Type::Insert && - otherMutation.parentShadowView.tag == parentTag) { - if (otherMutation.index <= adjustedIndex) { - adjustedIndex++; - } - } - } - - mutation = ShadowViewMutation::RemoveMutation( - mutation.parentShadowView, - mutation.oldChildShadowView, - adjustedIndex); - } - - keyFrame = AnimationKeyFrame{ - better::optional(mutation), - AnimationConfigurationType::Noop, - tag, - parent, - {}, - {}, - 0}; - } - - // Handle conflicting animations - for (auto &conflictingKeyframeTuple : conflictingAnimations) { - auto &conflictingKeyFrame = std::get<0>(conflictingKeyframeTuple); - auto const &conflictingMutationBaselineShadowView = - conflictingKeyFrame.viewStart; - - // We've found a conflict. - if (conflictingMutationBaselineShadowView.tag == tag) { - // What's the progress of this ongoing animation? - double conflictingAnimationProgress = - calculateAnimationProgress( - now, - *std::get<2>(conflictingKeyframeTuple), - std::get<1>(conflictingKeyframeTuple)) - .first; - - // Get a baseline ShadowView at the current progress of the - // inflight animation. TODO: handle multiple properties being - // animated separately? - auto interpolatedInflightShadowView = - createInterpolatedShadowView( - conflictingAnimationProgress, - std::get<1>(conflictingKeyframeTuple), - conflictingKeyFrame.viewStart, - conflictingKeyFrame.viewEnd); - - // Pick a Prop or layout property, depending on the current - // animation configuration. Figure out how much progress we've - // already made in the current animation, and start the animation - // from this point. - keyFrame.viewStart = interpolatedInflightShadowView; - keyFrame.initialProgress = getProgressThroughAnimation( - keyFrame, &animation, interpolatedInflightShadowView); - - // We're guaranteed that a tag only has one animation associated - // with it, so we can break here. If we support multiple - // animations and animation curves over the same tag in the - // future, this will need to be modified to support that. - break; - } - } - - keyFramesToAnimate.push_back(keyFrame); - } - } - -#ifdef RN_SHADOW_TREE_INTROSPECTION - { - std::stringstream ss(getDebugDescription(immediateMutations, {})); - std::string to; - while (std::getline(ss, to, '\n')) { - LOG(ERROR) - << "LayoutAnimationKeyFrameManager.cpp: got IMMEDIATE list: Line: " - << to; - } - } - - { - std::stringstream ss(getDebugDescription(mutationsToAnimate, {})); - std::string to; - while (std::getline(ss, to, '\n')) { - LOG(ERROR) - << "LayoutAnimationKeyFrameManager.cpp: got FINAL list: Line: " - << to; - } - } -#endif - - animation.keyFrames = keyFramesToAnimate; - inflightAnimations_.push_back(animation); - - // These will be executed immediately. - mutations = immediateMutations; - } /* if (currentAnimation) */ else { - // If there's no "next" animation, make sure we queue up "final" - // operations from all ongoing animations. - ShadowViewMutationList finalMutationsForConflictingAnimations{}; - for (auto &conflictingKeyframeTuple : conflictingAnimations) { - auto &keyFrame = std::get<0>(conflictingKeyframeTuple); - if (keyFrame.finalMutationForKeyFrame.hasValue()) { - finalMutationsForConflictingAnimations.push_back( - *keyFrame.finalMutationForKeyFrame); - } - } - - // Append mutations to this list and swap - so that the final - // conflicting mutations happen before any other mutations - finalMutationsForConflictingAnimations.insert( - finalMutationsForConflictingAnimations.end(), - mutations.begin(), - mutations.end()); - mutations = finalMutationsForConflictingAnimations; - - // Adjust pending mutation indices base on these operations - for (auto &mutation : mutations) { - if (mutation.type == ShadowViewMutation::Type::Insert || - mutation.type == ShadowViewMutation::Type::Remove) { - adjustDelayedMutationIndicesForMutation(surfaceId, mutation); - } - } - } - } // if (mutations) - - // We never commit a different root or modify anything - - // we just send additional mutations to the mounting layer until the - // animations are finished and the mounting layer (view) represents exactly - // what is in the most recent shadow tree - // Add animation mutations to the end of our existing mutations list in this - // function. - ShadowViewMutationList mutationsForAnimation{}; - animationMutationsForFrame(surfaceId, mutationsForAnimation, now); - - // Adjust pending mutation indices base on these operations - // For example: if a final "remove" mutation has been performed, and there is - // another that has not yet been executed because it is a part of an ongoing - // animation, its index may need to be adjusted. - for (auto const &animatedMutation : mutationsForAnimation) { - if (animatedMutation.type == ShadowViewMutation::Type::Insert || - animatedMutation.type == ShadowViewMutation::Type::Remove) { - adjustDelayedMutationIndicesForMutation(surfaceId, animatedMutation); - } - } - - mutations.insert( - mutations.end(), - mutationsForAnimation.begin(), - mutationsForAnimation.end()); - - // TODO: fill in telemetry - return MountingTransaction{ - surfaceId, transactionNumber, std::move(mutations), {}}; -} - -ComponentDescriptor const & -LayoutAnimationKeyFrameManager::getComponentDescriptorForShadowView( - ShadowView const &shadowView) const { - return componentDescriptorRegistry_->at(shadowView.componentHandle); -} - -void LayoutAnimationKeyFrameManager::setComponentDescriptorRegistry( - const SharedComponentDescriptorRegistry &componentDescriptorRegistry) { - componentDescriptorRegistry_ = componentDescriptorRegistry; -} - -/** - * 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 LayoutAnimationKeyFrameManager::createInterpolatedShadowView( - double progress, - AnimationConfig const &animationConfig, - ShadowView startingView, - ShadowView finalView) const { - ComponentDescriptor const &componentDescriptor = - getComponentDescriptorForShadowView(startingView); - auto mutatedShadowView = ShadowView(startingView); - - // Animate opacity or scale/transform - mutatedShadowView.props = componentDescriptor.interpolateProps( - progress, startingView.props, finalView.props); - - // Interpolate LayoutMetrics - LayoutMetrics const &finalLayoutMetrics = finalView.layoutMetrics; - LayoutMetrics const &baselineLayoutMetrics = startingView.layoutMetrics; - LayoutMetrics interpolatedLayoutMetrics = finalLayoutMetrics; - interpolatedLayoutMetrics.frame.origin.x = interpolateFloats( - progress, - baselineLayoutMetrics.frame.origin.x, - finalLayoutMetrics.frame.origin.x); - interpolatedLayoutMetrics.frame.origin.y = interpolateFloats( - progress, - baselineLayoutMetrics.frame.origin.y, - finalLayoutMetrics.frame.origin.y); - interpolatedLayoutMetrics.frame.size.width = interpolateFloats( - progress, - baselineLayoutMetrics.frame.size.width, - finalLayoutMetrics.frame.size.width); - interpolatedLayoutMetrics.frame.size.height = interpolateFloats( - progress, - baselineLayoutMetrics.frame.size.height, - finalLayoutMetrics.frame.size.height); - mutatedShadowView.layoutMetrics = interpolatedLayoutMetrics; - - return mutatedShadowView; -} - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/animations/LayoutAnimationKeyFrameManager.h b/ReactCommon/fabric/animations/LayoutAnimationKeyFrameManager.h deleted file mode 100644 index f286bd27a3..0000000000 --- a/ReactCommon/fabric/animations/LayoutAnimationKeyFrameManager.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its 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 - -namespace facebook { -namespace react { - -// This corresponds exactly with JS. -enum class AnimationType { - Spring, - Linear, - EaseInEaseOut, - EaseIn, - EaseOut, - Keyboard -}; -enum class AnimationProperty { - NotApplicable, - Opacity, - ScaleX, - ScaleY, - ScaleXY -}; -enum class AnimationConfigurationType { - Noop, // for animation placeholders that are not animated, and should be - // executed once other animations have completed - Create, - Update, - Delete -}; - -// This corresponds exactly with JS. -struct AnimationConfig { - AnimationType animationType; - AnimationProperty animationProperty; - double duration; // these are perhaps better represented as uint64_t, but they - // come from JS as doubles - double delay; - double springDamping; - double initialVelocity; -}; - -// This corresponds exactly with JS. -struct LayoutAnimationConfig { - double duration; // ms - better::optional createConfig; - better::optional updateConfig; - better::optional deleteConfig; -}; - -struct AnimationKeyFrame { - // The mutation that should be executed once the animation completes - // (optional). - better::optional finalMutationForKeyFrame; - - // The type of animation this is (for configuration purposes) - AnimationConfigurationType type; - - // Tag representing the node being animated. - Tag tag; - - ShadowView parentView; - - // ShadowView representing the start and end points of this animation. - ShadowView viewStart; - ShadowView viewEnd; - - // If an animation interrupts an existing one, the starting state may actually - // be halfway through the intended transition. - double initialProgress; -}; - -struct LayoutAnimation { - SurfaceId surfaceId; - uint64_t startTime; - bool completed = false; - LayoutAnimationConfig layoutAnimationConfig; - std::shared_ptr successCallback; - std::shared_ptr errorCallback; - std::vector keyFrames; -}; - -class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate, - public MountingOverrideDelegate { - public: - void uiManagerDidConfigureNextLayoutAnimation( - RawValue const &config, - std::shared_ptr successCallback, - std::shared_ptr errorCallback) const override; - void setComponentDescriptorRegistry(SharedComponentDescriptorRegistry const & - componentDescriptorRegistry) override; - - // TODO: add SurfaceId to this API as well - bool shouldAnimateFrame() const override; - - 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. - better::optional pullTransaction( - SurfaceId surfaceId, - MountingTransaction::Number number, - MountingTelemetry const &telemetry, - ShadowViewMutationList mutations) const override; - - private: - void adjustDelayedMutationIndicesForMutation( - SurfaceId surfaceId, - ShadowViewMutation const &mutation) const; - - protected: - ComponentDescriptor const &getComponentDescriptorForShadowView( - ShadowView const &shadowView) const; - std::pair calculateAnimationProgress( - uint64_t now, - LayoutAnimation const &animation, - AnimationConfig const &mutationConfig) const; - - ShadowView createInterpolatedShadowView( - double progress, - AnimationConfig const &animationConfig, - ShadowView startingView, - ShadowView finalView) const; - - virtual void animationMutationsForFrame( - SurfaceId surfaceId, - ShadowViewMutation::List &mutationsList, - uint64_t now) const = 0; - - virtual double getProgressThroughAnimation( - AnimationKeyFrame const &keyFrame, - LayoutAnimation const *layoutAnimation, - ShadowView const &animationStateView) const = 0; - - SharedComponentDescriptorRegistry componentDescriptorRegistry_; - mutable better::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_{}; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/core/primitives/RawValue.h b/ReactCommon/fabric/core/primitives/RawValue.h index 75c2e9527a..67f6ac05dc 100644 --- a/ReactCommon/fabric/core/primitives/RawValue.h +++ b/ReactCommon/fabric/core/primitives/RawValue.h @@ -64,7 +64,6 @@ class RawValue { private: friend class RawProps; friend class RawPropsParser; - friend class UIManagerBinding; /* * Arbitrary constructors are private only for RawProps and internal usage. @@ -74,9 +73,9 @@ class RawValue { RawValue(folly::dynamic &&dynamic) noexcept : dynamic_(std::move(dynamic)){}; /* - * Copy constructor and copy assignment operator would be private and only for - * internal use, but it's needed for user-code that does `auto val = - * (better::map)rawVal;` + * Copy constructor and copy assignment operator are private and only for + * internal use. Basically, it's implementation details. Other particular + * implementations of the `RawValue` interface may not have them. */ RawValue(RawValue const &other) noexcept : dynamic_(other.dynamic_) {} diff --git a/ReactCommon/fabric/mounting/MountingCoordinator.cpp b/ReactCommon/fabric/mounting/MountingCoordinator.cpp index ad1552f156..158959d40d 100644 --- a/ReactCommon/fabric/mounting/MountingCoordinator.cpp +++ b/ReactCommon/fabric/mounting/MountingCoordinator.cpp @@ -19,12 +19,9 @@ namespace facebook { namespace react { -MountingCoordinator::MountingCoordinator( - ShadowTreeRevision baseRevision, - MountingOverrideDelegate *delegate) +MountingCoordinator::MountingCoordinator(ShadowTreeRevision baseRevision) : surfaceId_(baseRevision.getRootShadowNode().getSurfaceId()), - baseRevision_(baseRevision), - mountingOverrideDelegate_(delegate) { + baseRevision_(baseRevision) { #ifdef RN_SHADOW_TREE_INTROSPECTION stubViewTree_ = stubViewTreeFromShadowNode(baseRevision_.getRootShadowNode()); #endif @@ -69,30 +66,31 @@ bool MountingCoordinator::waitForTransaction( lock, timeout, [this]() { return lastRevision_.has_value(); }); } -void MountingCoordinator::updateBaseRevision( - ShadowTreeRevision const &baseRevision) const { - baseRevision_ = std::move(baseRevision); -} +better::optional MountingCoordinator::pullTransaction() + const { + std::lock_guard lock(mutex_); -void MountingCoordinator::resetLatestRevision() const { - lastRevision_.reset(); -} - -#ifdef RN_SHADOW_TREE_INTROSPECTION -void MountingCoordinator::validateTransactionAgainstStubViewTree( - ShadowViewMutationList const &mutations, - bool assertEquality) const { - std::string line; - - std::stringstream ssMutations(getDebugDescription(mutations, {})); - while (std::getline(ssMutations, line, '\n')) { - LOG(ERROR) << "Mutations:" << line; + if (!lastRevision_.has_value()) { + return {}; } + number_++; + + auto telemetry = lastRevision_->getTelemetry(); + telemetry.willDiff(); + + auto mutations = calculateShadowViewMutations( + baseRevision_.getRootShadowNode(), lastRevision_->getRootShadowNode()); + + telemetry.didDiff(); + +#ifdef RN_SHADOW_TREE_INTROSPECTION stubViewTree_.mutate(mutations); auto stubViewTree = stubViewTreeFromShadowNode(lastRevision_->getRootShadowNode()); + std::string line; + std::stringstream ssOldTree( baseRevision_.getRootShadowNode().getDebugDescription()); while (std::getline(ssOldTree, line, '\n')) { @@ -105,65 +103,19 @@ void MountingCoordinator::validateTransactionAgainstStubViewTree( LOG(ERROR) << "New tree:" << line; } - if (assertEquality) { - assert(stubViewTree_ == stubViewTree); + std::stringstream ssMutations(getDebugDescription(mutations, {})); + while (std::getline(ssMutations, line, '\n')) { + LOG(ERROR) << "Mutations:" << line; } -} + + assert(stubViewTree_ == stubViewTree); #endif -better::optional MountingCoordinator::pullTransaction() - const { - std::lock_guard lock(mutex_); + baseRevision_ = std::move(*lastRevision_); + lastRevision_.reset(); - bool shouldOverridePullTransaction = mountingOverrideDelegate_ != nullptr && - mountingOverrideDelegate_->shouldOverridePullTransaction(); - - if (!shouldOverridePullTransaction && !lastRevision_.has_value()) { - return {}; - } - - number_++; - - ShadowViewMutation::List diffMutations{}; - auto telemetry = - (lastRevision_.hasValue() ? lastRevision_->getTelemetry() - : MountingTelemetry{}); - if (lastRevision_.hasValue()) { - telemetry.willDiff(); - - diffMutations = calculateShadowViewMutations( - baseRevision_.getRootShadowNode(), lastRevision_->getRootShadowNode()); - - telemetry.didDiff(); - } - - better::optional transaction{}; - - // The override delegate can provide custom mounting instructions, - // even if there's no `lastRevision_`. Consider cases of animation frames - // in between React tree updates. - if (shouldOverridePullTransaction) { - transaction = mountingOverrideDelegate_->pullTransaction( - surfaceId_, number_, telemetry, std::move(diffMutations)); - } else if (lastRevision_.hasValue()) { - transaction = MountingTransaction{ - surfaceId_, number_, std::move(diffMutations), telemetry}; - } - - if (lastRevision_.hasValue()) { -#ifdef RN_SHADOW_TREE_INTROSPECTION - // Only validate non-animated transactions - it's garbage to validate - // animated transactions, since the stub view tree likely won't match - // the committed tree during an animation. - this->validateTransactionAgainstStubViewTree( - transaction->getMutations(), !shouldOverridePullTransaction); -#endif - - baseRevision_ = std::move(*lastRevision_); - lastRevision_.reset(); - } - - return transaction; + return MountingTransaction{ + surfaceId_, number_, std::move(mutations), telemetry}; } } // namespace react diff --git a/ReactCommon/fabric/mounting/MountingCoordinator.h b/ReactCommon/fabric/mounting/MountingCoordinator.h index 6976f35f48..e4389d6421 100644 --- a/ReactCommon/fabric/mounting/MountingCoordinator.h +++ b/ReactCommon/fabric/mounting/MountingCoordinator.h @@ -11,10 +11,8 @@ #include #include -#include #include #include -#include "ShadowTreeRevision.h" #ifdef RN_SHADOW_TREE_INTROSPECTION #include @@ -35,12 +33,10 @@ class MountingCoordinator final { using Shared = std::shared_ptr; /* - * The constructor is meant to be used only inside `ShadowTree`, and it's + * The constructor is ment to be used only inside `ShadowTree`, and it's * `public` only to enable using with `std::make_shared<>`. */ - MountingCoordinator( - ShadowTreeRevision baseRevision, - MountingOverrideDelegate *delegate); + MountingCoordinator(ShadowTreeRevision baseRevision); /* * Returns the id of the surface that the coordinator belongs to. @@ -69,20 +65,12 @@ class MountingCoordinator final { */ bool waitForTransaction(std::chrono::duration timeout) const; - /* - * Methods from this section are meant to be used by - * `MountingOverrideDelegate` only. - */ - public: - void updateBaseRevision(ShadowTreeRevision const &baseRevision) const; - void resetLatestRevision() const; + private: + friend class ShadowTree; /* * Methods from this section are meant to be used by `ShadowTree` only. */ - private: - friend class ShadowTree; - void push(ShadowTreeRevision &&revision) const; /* @@ -90,7 +78,7 @@ class MountingCoordinator final { * Generating a `MountingTransaction` requires some resources which the * `MountingCoordinator` does not own (e.g. `ComponentDescriptor`s). Revoking * committed revisions allows the owner (a Shadow Tree) to make sure that - * those resources will not be accessed (e.g. by the Mounting Layer). + * those resources will not be accessed (e.g. by the Mouting Layer). */ void revoke() const; @@ -102,12 +90,8 @@ class MountingCoordinator final { mutable better::optional lastRevision_{}; mutable MountingTransaction::Number number_{0}; mutable std::condition_variable signal_; - mutable MountingOverrideDelegate *mountingOverrideDelegate_{nullptr}; #ifdef RN_SHADOW_TREE_INTROSPECTION - void validateTransactionAgainstStubViewTree( - ShadowViewMutationList const &mutations, - bool assertEquality) const; mutable StubViewTree stubViewTree_; // Protected by `mutex_`. #endif }; diff --git a/ReactCommon/fabric/mounting/MountingOverrideDelegate.h b/ReactCommon/fabric/mounting/MountingOverrideDelegate.h deleted file mode 100644 index af7d7d6fa7..0000000000 --- a/ReactCommon/fabric/mounting/MountingOverrideDelegate.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#pragma once - -namespace facebook { -namespace react { - -class MountingCoordinator; - -/** - * Generic interface for anything that needs to override specific - * MountingCoordinator methods. This is for platform-specific escape hatches - * like animations. - */ -class MountingOverrideDelegate { - public: - virtual bool shouldOverridePullTransaction() const = 0; - - /** - * Delegates that override this method are responsible for: - * - * - Returning a MountingTransaction with mutations - * - Calling - * - Telemetry, if appropriate - * - * @param surfaceId - * @param number - * @param mountingCoordinator - * @return - */ - virtual better::optional pullTransaction( - SurfaceId surfaceId, - MountingTransaction::Number number, - MountingTelemetry const &telemetry, - ShadowViewMutationList mutations) const = 0; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/mounting/MountingTransaction.h b/ReactCommon/fabric/mounting/MountingTransaction.h index 0a0c68ab6d..a13526f8a9 100644 --- a/ReactCommon/fabric/mounting/MountingTransaction.h +++ b/ReactCommon/fabric/mounting/MountingTransaction.h @@ -18,7 +18,7 @@ namespace react { * particularly list of mutations and meta-data associated with the commit. * Movable and copyable, but moving is strongly encouraged. * Beware: A moved-from object of this type has unspecified value and accessing - * that is UB (Undefined Behaviour). + * that is UB. */ class MountingTransaction final { public: diff --git a/ReactCommon/fabric/mounting/ShadowTree.cpp b/ReactCommon/fabric/mounting/ShadowTree.cpp index d6a40be917..a6e4c2c58e 100644 --- a/ReactCommon/fabric/mounting/ShadowTree.cpp +++ b/ReactCommon/fabric/mounting/ShadowTree.cpp @@ -221,8 +221,7 @@ ShadowTree::ShadowTree( LayoutConstraints const &layoutConstraints, LayoutContext const &layoutContext, RootComponentDescriptor const &rootComponentDescriptor, - ShadowTreeDelegate const &delegate, - MountingOverrideDelegate *mountingOverrideDelegate) + ShadowTreeDelegate const &delegate) : surfaceId_(surfaceId), delegate_(delegate) { const auto noopEventEmitter = std::make_shared( nullptr, -1, std::shared_ptr()); @@ -241,7 +240,7 @@ ShadowTree::ShadowTree( family)); mountingCoordinator_ = std::make_shared( - ShadowTreeRevision{rootShadowNode_, 0, {}}, mountingOverrideDelegate); + ShadowTreeRevision{rootShadowNode_, 0, {}}); } ShadowTree::~ShadowTree() { @@ -358,7 +357,7 @@ bool ShadowTree::tryCommit( mountingCoordinator_->push( ShadowTreeRevision{newRootShadowNode, revisionNumber, telemetry}); - notifyDelegatesOfUpdates(); + delegate_.shadowTreeDidFinishTransaction(*this, mountingCoordinator_); return true; } @@ -399,9 +398,5 @@ void ShadowTree::emitLayoutEvents( } } -void ShadowTree::notifyDelegatesOfUpdates() const { - delegate_.shadowTreeDidFinishTransaction(*this, mountingCoordinator_); -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/mounting/ShadowTree.h b/ReactCommon/fabric/mounting/ShadowTree.h index a4606ba9a8..f0c904d515 100644 --- a/ReactCommon/fabric/mounting/ShadowTree.h +++ b/ReactCommon/fabric/mounting/ShadowTree.h @@ -18,7 +18,6 @@ #include #include #include -#include "MountingOverrideDelegate.h" namespace facebook { namespace react { @@ -39,8 +38,7 @@ class ShadowTree final { LayoutConstraints const &layoutConstraints, LayoutContext const &layoutContext, RootComponentDescriptor const &rootComponentDescriptor, - ShadowTreeDelegate const &delegate, - MountingOverrideDelegate *mountingOverrideDelegate); + ShadowTreeDelegate const &delegate); ~ShadowTree(); @@ -71,13 +69,6 @@ class ShadowTree final { */ void commitEmptyTree() const; - /** - * Forces the ShadowTree to ping its delegate that an update is available. - * Useful for animations on Android. - * @return - */ - void notifyDelegatesOfUpdates() const; - MountingCoordinator::Shared getMountingCoordinator() const; /* diff --git a/ReactCommon/fabric/mounting/ShadowTreeRevision.cpp b/ReactCommon/fabric/mounting/ShadowTreeRevision.cpp index 46f59d0418..7e13c85540 100644 --- a/ReactCommon/fabric/mounting/ShadowTreeRevision.cpp +++ b/ReactCommon/fabric/mounting/ShadowTreeRevision.cpp @@ -22,10 +22,6 @@ MountingTelemetry const &ShadowTreeRevision::getTelemetry() const { return telemetry_; } -ShadowNode::Shared ShadowTreeRevision::getSharedRootShadowNode() { - return rootShadowNode_; -} - ShadowNode const &ShadowTreeRevision::getRootShadowNode() { return *rootShadowNode_; } diff --git a/ReactCommon/fabric/mounting/ShadowTreeRevision.h b/ReactCommon/fabric/mounting/ShadowTreeRevision.h index ba89dc784f..71f68d0ed6 100644 --- a/ReactCommon/fabric/mounting/ShadowTreeRevision.h +++ b/ReactCommon/fabric/mounting/ShadowTreeRevision.h @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -43,21 +42,14 @@ class ShadowTreeRevision final { */ MountingTelemetry const &getTelemetry() const; - /* - * Methods from this section are meant to be used by - * `MountingOverrideDelegate` only. - */ - public: - ShadowNode const &getRootShadowNode(); - ShadowNode::Shared getSharedRootShadowNode(); + private: + friend class MountingCoordinator; /* * Methods from this section are meant to be used by `MountingCoordinator` * only. */ - private: - friend class MountingCoordinator; - + ShadowNode const &getRootShadowNode(); Number getNumber() const; private: diff --git a/ReactCommon/fabric/mounting/ShadowView.cpp b/ReactCommon/fabric/mounting/ShadowView.cpp index a5436df7dc..800308add5 100644 --- a/ReactCommon/fabric/mounting/ShadowView.cpp +++ b/ReactCommon/fabric/mounting/ShadowView.cpp @@ -13,10 +13,10 @@ namespace facebook { namespace react { static LayoutMetrics layoutMetricsFromShadowNode(ShadowNode const &shadowNode) { - auto layoutableShadowNode = + auto layotableShadowNode = traitCast(&shadowNode); - return layoutableShadowNode ? layoutableShadowNode->getLayoutMetrics() - : EmptyLayoutMetrics; + return layotableShadowNode ? layotableShadowNode->getLayoutMetrics() + : EmptyLayoutMetrics; } ShadowView::ShadowView(const ShadowNode &shadowNode) diff --git a/ReactCommon/fabric/mounting/ShadowView.h b/ReactCommon/fabric/mounting/ShadowView.h index fc51f9e9b1..1372b44928 100644 --- a/ReactCommon/fabric/mounting/ShadowView.h +++ b/ReactCommon/fabric/mounting/ShadowView.h @@ -66,7 +66,7 @@ struct ShadowViewNodePair final { ShadowNode const *shadowNode; /* - * The stored pointer to `ShadowNode` represents an identity of the pair. + * The stored pointer to `ShadowNode` represents an indentity of the pair. */ bool operator==(const ShadowViewNodePair &rhs) const; bool operator!=(const ShadowViewNodePair &rhs) const; diff --git a/ReactCommon/fabric/mounting/tests/StateReconciliationTest.cpp b/ReactCommon/fabric/mounting/tests/StateReconciliationTest.cpp index 665f18bcf6..19ba086ca2 100644 --- a/ReactCommon/fabric/mounting/tests/StateReconciliationTest.cpp +++ b/ReactCommon/fabric/mounting/tests/StateReconciliationTest.cpp @@ -103,8 +103,7 @@ TEST(StateReconciliationTest, testStateReconciliation) { LayoutConstraints{}, LayoutContext{}, rootComponentDescriptor, - shadowTreeDelegate, - nullptr}; + shadowTreeDelegate}; shadowTree.commit( [&](RootShadowNode::Shared const &oldRootShadowNode) { diff --git a/ReactCommon/fabric/scheduler/Scheduler.cpp b/ReactCommon/fabric/scheduler/Scheduler.cpp index d4dafd716b..1acdf65a17 100644 --- a/ReactCommon/fabric/scheduler/Scheduler.cpp +++ b/ReactCommon/fabric/scheduler/Scheduler.cpp @@ -13,23 +13,15 @@ #include #include #include -#include -#include #include #include #include -#ifdef RN_SHADOW_TREE_INTROSPECTION -#include -#include -#endif - namespace facebook { namespace react { Scheduler::Scheduler( SchedulerToolbox schedulerToolbox, - UIManagerAnimationDelegate *animationDelegate, SchedulerDelegate *delegate) { runtimeExecutor_ = schedulerToolbox.runtimeExecutor; @@ -98,12 +90,6 @@ Scheduler::Scheduler( delegate_ = delegate; uiManager_ = uiManager; - if (animationDelegate != nullptr) { - animationDelegate->setComponentDescriptorRegistry( - componentDescriptorRegistry_); - } - uiManager_->setAnimationDelegate(animationDelegate); - #ifdef ANDROID enableNewStateReconciliation_ = reactNativeConfig_->getBool( "react_fabric:enable_new_state_reconciliation_android"); @@ -172,8 +158,7 @@ void Scheduler::startSurface( const std::string &moduleName, const folly::dynamic &initialProps, const LayoutConstraints &layoutConstraints, - const LayoutContext &layoutContext, - MountingOverrideDelegate *mountingOverrideDelegate) const { + const LayoutContext &layoutContext) const { SystraceSection s("Scheduler::startSurface"); auto shadowTree = std::make_unique( @@ -181,8 +166,7 @@ void Scheduler::startSurface( layoutConstraints, layoutContext, *rootComponentDescriptor_, - *uiManager_, - mountingOverrideDelegate); + *uiManager_); shadowTree->setEnableNewStateReconciliation(enableNewStateReconciliation_); @@ -326,12 +310,6 @@ SchedulerDelegate *Scheduler::getDelegate() const { return delegate_; } -#pragma mark - UIManagerAnimationDelegate - -void Scheduler::animationTick() const { - uiManager_->animationTick(); -} - #pragma mark - UIManagerDelegate void Scheduler::uiManagerDidFinishTransaction( @@ -342,6 +320,7 @@ void Scheduler::uiManagerDidFinishTransaction( delegate_->schedulerDidFinishTransaction(mountingCoordinator); } } + void Scheduler::uiManagerDidCreateShadowNode( const ShadowNode::Shared &shadowNode) { SystraceSection s("Scheduler::uiManagerDidCreateShadowNode"); diff --git a/ReactCommon/fabric/scheduler/Scheduler.h b/ReactCommon/fabric/scheduler/Scheduler.h index 9ee114ec21..243db58a0e 100644 --- a/ReactCommon/fabric/scheduler/Scheduler.h +++ b/ReactCommon/fabric/scheduler/Scheduler.h @@ -12,14 +12,13 @@ #include #include +#include #include #include #include #include -#include #include #include -#include #include #include #include @@ -32,10 +31,7 @@ namespace react { */ class Scheduler final : public UIManagerDelegate { public: - Scheduler( - SchedulerToolbox schedulerToolbox, - UIManagerAnimationDelegate *animationDelegate, - SchedulerDelegate *delegate); + Scheduler(SchedulerToolbox schedulerToolbox, SchedulerDelegate *delegate); ~Scheduler(); #pragma mark - Surface Management @@ -45,8 +41,7 @@ class Scheduler final : public UIManagerDelegate { const std::string &moduleName, const folly::dynamic &initialProps, const LayoutConstraints &layoutConstraints = {}, - const LayoutContext &layoutContext = {}, - MountingOverrideDelegate *mountingOverrideDelegate = nullptr) const; + const LayoutContext &layoutContext = {}) const; void renderTemplateToSurface( SurfaceId surfaceId, @@ -93,13 +88,6 @@ class Scheduler final : public UIManagerDelegate { void setDelegate(SchedulerDelegate *delegate); SchedulerDelegate *getDelegate() const; -#pragma mark - UIManagerAnimationDelegate - // This is not needed on iOS or any platform that has a "pull" instead of - // "push" MountingCoordinator model. This just tells the delegate an update - // is available and that it should `pullTransaction`; we may want to rename - // this to be more generic and not animation-specific. - void animationTick() const; - #pragma mark - UIManagerDelegate void uiManagerDidFinishTransaction( diff --git a/ReactCommon/fabric/uimanager/UIManager.cpp b/ReactCommon/fabric/uimanager/UIManager.cpp index b4910cee67..761a87c3ef 100644 --- a/ReactCommon/fabric/uimanager/UIManager.cpp +++ b/ReactCommon/fabric/uimanager/UIManager.cpp @@ -268,15 +268,9 @@ void UIManager::dispatchCommand( } void UIManager::configureNextLayoutAnimation( - RawValue const &config, + const folly::dynamic config, SharedEventTarget successCallback, - SharedEventTarget errorCallback) const { - if (animationDelegate_) { - animationDelegate_->uiManagerDidConfigureNextLayoutAnimation( - config, successCallback, errorCallback); - } -} - + SharedEventTarget errorCallback) const {} void UIManager::setComponentDescriptorRegistry( const SharedComponentDescriptorRegistry &componentDescriptorRegistry) { componentDescriptorRegistry_ = componentDescriptorRegistry; @@ -316,22 +310,5 @@ void UIManager::shadowTreeDidFinishTransaction( } } -#pragma mark - UIManagerAnimationDelegate - -void UIManager::setAnimationDelegate( - UIManagerAnimationDelegate *delegate) const { - animationDelegate_ = delegate; -} - -void UIManager::animationTick() { - if (animationDelegate_ != nullptr && - animationDelegate_->shouldAnimateFrame()) { - shadowTreeRegistry_.enumerate( - [&](ShadowTree const &shadowTree, bool &stop) { - shadowTree.notifyDelegatesOfUpdates(); - }); - } -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/uimanager/UIManager.h b/ReactCommon/fabric/uimanager/UIManager.h index 543bf97cfa..51131dd98d 100644 --- a/ReactCommon/fabric/uimanager/UIManager.h +++ b/ReactCommon/fabric/uimanager/UIManager.h @@ -12,13 +12,11 @@ #include #include -#include #include #include #include #include #include -#include #include namespace facebook { @@ -41,15 +39,6 @@ class UIManager final : public ShadowTreeDelegate { void setDelegate(UIManagerDelegate *delegate); UIManagerDelegate *getDelegate(); - /** - * Sets and gets the UIManager's Animation APIs delegate. - * The delegate is stored as a raw pointer, so the owner must null - * the pointer before being destroyed. - */ - void setAnimationDelegate(UIManagerAnimationDelegate *delegate) const; - - void animationTick(); - /* * Provides access to a UIManagerBindging. * The `callback` methods will not be called if the internal pointer to @@ -132,15 +121,13 @@ class UIManager final : public ShadowTreeDelegate { * This API configures a global LayoutAnimation starting from the root node. */ void configureNextLayoutAnimation( - RawValue const &config, + const folly::dynamic config, SharedEventTarget successCallback, SharedEventTarget errorCallback) const; - ShadowTreeRegistry const &getShadowTreeRegistry() const; SharedComponentDescriptorRegistry componentDescriptorRegistry_; UIManagerDelegate *delegate_; - mutable UIManagerAnimationDelegate *animationDelegate_{nullptr}; UIManagerBinding *uiManagerBinding_; ShadowTreeRegistry shadowTreeRegistry_{}; }; diff --git a/ReactCommon/fabric/uimanager/UIManagerAnimationDelegate.h b/ReactCommon/fabric/uimanager/UIManagerAnimationDelegate.h deleted file mode 100644 index a5d8c5465a..0000000000 --- a/ReactCommon/fabric/uimanager/UIManagerAnimationDelegate.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its 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 - -namespace facebook { -namespace react { - -class UIManagerAnimationDelegate { - public: - /* - * Configure a LayoutAnimation. - * TODO: need SurfaceId here - */ - virtual void uiManagerDidConfigureNextLayoutAnimation( - RawValue const &config, - SharedEventTarget successCallback, - SharedEventTarget errorCallback) const = 0; - - /** - * Set ComponentDescriptor registry. - * - * @param componentDescriptorRegistry - */ - virtual void setComponentDescriptorRegistry( - const SharedComponentDescriptorRegistry &componentDescriptorRegistry) = 0; - - /** - * Only needed on Android to drive animations. - */ - virtual bool shouldAnimateFrame() const = 0; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index 92d20a915c..4c50095e44 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -619,14 +619,16 @@ jsi::Value UIManagerBinding::get( const jsi::Value *arguments, size_t count) -> jsi::Value { uiManager->configureNextLayoutAnimation( - // TODO: pass in JSI value instead of folly::dynamic to RawValue - RawValue(commandArgsFromValue(runtime, arguments[0])), + commandArgsFromValue( + runtime, + arguments[0]), // TODO T66507273: do a better job of parsing + // these arguments into a real struct / use a + // C++ typed object instead of folly::dynamic eventTargetFromValue(runtime, arguments[1], -1), eventTargetFromValue(runtime, arguments[2], -1)); return jsi::Value::undefined(); }); } - return jsi::Value::undefined(); } diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.h b/ReactCommon/fabric/uimanager/UIManagerBinding.h index 0ecf00c9dd..75485e6c8c 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.h +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.h @@ -9,7 +9,6 @@ #include #include -#include #include #include