diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp new file mode 100644 index 00000000000000..c7e4be27701232 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp @@ -0,0 +1,130 @@ +/* + * 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. + */ + +#include +#include "AnimatedPropsSerializer.h" + +namespace facebook::react { + +namespace { + +void packBorderRadiusCorner( + folly::dynamic& dyn, + const std::string& propName, + const std::optional& cornerValue) { + if (cornerValue.has_value()) { + dyn.insert(propName, cornerValue.value().value); + } +} + +void packBorderRadii( + folly::dynamic& dyn, + const AnimatedPropBase& animatedProp) { + const auto& borderRadii = get(animatedProp); + + packBorderRadiusCorner(dyn, "borderTopRightRadius", borderRadii.topRight); + packBorderRadiusCorner(dyn, "borderTopLeftRadius", borderRadii.topLeft); + packBorderRadiusCorner( + dyn, "borderBottomRightRadius", borderRadii.bottomRight); + packBorderRadiusCorner(dyn, "borderBottomLeftRadius", borderRadii.bottomLeft); + packBorderRadiusCorner(dyn, "borderTopStartRadius", borderRadii.topStart); + packBorderRadiusCorner(dyn, "borderTopEndRadius", borderRadii.topEnd); + packBorderRadiusCorner( + dyn, "borderBottomStartRadius", borderRadii.bottomStart); + packBorderRadiusCorner(dyn, "borderBottomEndRadius", borderRadii.bottomEnd); + packBorderRadiusCorner(dyn, "borderStartStartRadius", borderRadii.startStart); + packBorderRadiusCorner(dyn, "borderStartEndRadius", borderRadii.startEnd); + packBorderRadiusCorner(dyn, "borderEndStartRadius", borderRadii.endStart); + packBorderRadiusCorner(dyn, "borderEndEndRadius", borderRadii.endEnd); + + if (borderRadii.all.has_value()) { + dyn.insert("borderRadius", borderRadii.all.value().value); + } +} + +void packOpacity(folly::dynamic& dyn, const AnimatedPropBase& animatedProp) { + dyn.insert("opacity", get(animatedProp)); +} + +void packTransform(folly::dynamic& dyn, const AnimatedPropBase& animatedProp) { + const auto transform = get(animatedProp); + const auto matrixArray = folly::dynamic::array( + transform.matrix[0], + transform.matrix[1], + transform.matrix[2], + transform.matrix[3], + transform.matrix[4], + transform.matrix[5], + transform.matrix[6], + transform.matrix[7], + transform.matrix[8], + transform.matrix[9], + transform.matrix[10], + transform.matrix[11], + transform.matrix[12], + transform.matrix[13], + transform.matrix[14], + transform.matrix[15]); + dyn.insert( + "transform", + folly::dynamic::array(folly::dynamic::object("matrix", matrixArray))); +} + +void packBackgroundColor( + folly::dynamic& dyn, + const AnimatedPropBase& animatedProp) { + const auto& backgroundColor = get(animatedProp); + if (backgroundColor) { + dyn.insert("backgroundColor", static_cast(*backgroundColor)); + } +} + +void packAnimatedProp( + folly::dynamic& dyn, + const std::unique_ptr& animatedProp) { + switch (animatedProp->propName) { + case OPACITY: + packOpacity(dyn, *animatedProp); + break; + + case TRANSFORM: + packTransform(dyn, *animatedProp); + break; + + case BACKGROUND_COLOR: + packBackgroundColor(dyn, *animatedProp); + break; + + case BORDER_RADII: + packBorderRadii(dyn, *animatedProp); + break; + + case WIDTH: + case HEIGHT: + case FLEX: + throw std::runtime_error("Tried to synchronously update layout props"); + } +} + +} // namespace + +namespace animationbackend { + +folly::dynamic packAnimatedProps(const AnimatedProps& animatedProps) { + auto dyn = animatedProps.rawProps ? animatedProps.rawProps->toDynamic() + : folly::dynamic::object(); + + for (auto& animatedProp : animatedProps.props) { + packAnimatedProp(dyn, animatedProp); + } + + return dyn; +} + +} // namespace animationbackend + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h index 868a8611e8d65f..ef496b5fb639b6 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h @@ -12,7 +12,7 @@ namespace facebook::react { -enum PropName { OPACITY, WIDTH, HEIGHT, BORDER_RADII, FLEX, TRANSFORM }; +enum PropName { OPACITY, WIDTH, HEIGHT, BORDER_RADII, FLEX, TRANSFORM, BACKGROUND_COLOR }; struct AnimatedPropBase { PropName propName; @@ -70,6 +70,10 @@ inline void cloneProp(BaseViewProps &viewProps, const AnimatedPropBase &animated case TRANSFORM: viewProps.transform = get(animatedProp); break; + + case BACKGROUND_COLOR: + viewProps.backgroundColor = get(animatedProp); + break; } } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsBuilder.h b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsBuilder.h index e52b73bc78d51c..4d10ba7e85bf2a 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsBuilder.h +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsBuilder.h @@ -35,6 +35,10 @@ struct AnimatedPropsBuilder { { props.push_back(std::make_unique>(TRANSFORM, std::move(t))); } + void setBackgroundColor(SharedColor value) + { + props.push_back(std::make_unique>(BACKGROUND_COLOR, value)); + } void storeDynamic(folly::dynamic &d) { rawProps = std::make_unique(std::move(d)); diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsSerializer.h b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsSerializer.h new file mode 100644 index 00000000000000..7d568160ec3680 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedPropsSerializer.h @@ -0,0 +1,17 @@ +/* + * 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 "AnimatedProps.h" + +namespace facebook::react::animationbackend { + +folly::dynamic packAnimatedProps(const AnimatedProps &animatedProps); + +} // namespace facebook::react::animationbackend diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp index 8ab5f07ba97319..308f19922a08c5 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp @@ -6,6 +6,8 @@ */ #include "AnimationBackend.h" +#include +#include #include namespace facebook::react { @@ -156,28 +158,10 @@ void AnimationBackend::commitUpdates( void AnimationBackend::synchronouslyUpdateProps( const std::unordered_map& updates) { for (auto& [tag, animatedProps] : updates) { - auto dyn = animatedProps.rawProps ? animatedProps.rawProps->toDynamic() - : folly::dynamic::object(); - for (auto& animatedProp : animatedProps.props) { - // TODO: We shouldn't repack it into dynamic, but for that a rewrite of - // directManipulationCallback_ is needed - switch (animatedProp->propName) { - case OPACITY: - dyn.insert("opacity", get(animatedProp)); - break; - - case BORDER_RADII: - case TRANSFORM: - // TODO: handle other things than opacity - break; - - case WIDTH: - case HEIGHT: - case FLEX: - throw "Tried to synchronously update layout props"; - } - } - directManipulationCallback_(tag, dyn); + // TODO: We shouldn't repack it into dynamic, but for that a rewrite of + // directManipulationCallback_ is needed + auto dyn = animationbackend::packAnimatedProps(animatedProps); + directManipulationCallback_(tag, std::move(dyn)); } }