first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
/*
* 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 <react/renderer/components/view/BaseViewProps.h>
#include <utility>
namespace facebook::react {
enum PropName { OPACITY, WIDTH, HEIGHT, BORDER_RADII, FLEX, TRANSFORM };
struct AnimatedPropBase {
PropName propName;
explicit AnimatedPropBase(PropName propName) : propName(propName) {}
virtual ~AnimatedPropBase() = default;
};
template <typename T>
struct AnimatedProp : AnimatedPropBase {
T value;
AnimatedProp() = default;
AnimatedProp(PropName propName, const T &value) : AnimatedPropBase{propName}, value(std::move(value)) {}
};
template <typename T>
T get(const std::unique_ptr<AnimatedPropBase> &animatedProp)
{
return static_cast<AnimatedProp<T> *>(animatedProp.get())->value;
}
struct AnimatedProps {
std::vector<std::unique_ptr<AnimatedPropBase>> props;
std::unique_ptr<RawProps> rawProps;
};
} // namespace facebook::react

View File

@@ -0,0 +1,52 @@
/*
* 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 <react/renderer/components/view/BaseViewProps.h>
#include "AnimatedProps.h"
namespace facebook::react {
struct AnimatedPropsBuilder {
std::vector<std::unique_ptr<AnimatedPropBase>> props;
std::unique_ptr<RawProps> rawProps;
void setOpacity(Float value)
{
props.push_back(std::make_unique<AnimatedProp<Float>>(OPACITY, value));
}
void setWidth(yoga::Style::SizeLength value)
{
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(WIDTH, value));
}
void setHeight(yoga::Style::SizeLength value)
{
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(HEIGHT, value));
}
void setBorderRadii(CascadedBorderRadii &value)
{
props.push_back(std::make_unique<AnimatedProp<CascadedBorderRadii>>(BORDER_RADII, value));
}
void setTransform(Transform &t)
{
props.push_back(std::make_unique<AnimatedProp<Transform>>(TRANSFORM, std::move(t)));
}
void storeDynamic(folly::dynamic &d)
{
rawProps = std::make_unique<RawProps>(std::move(d));
}
void storeJSI(jsi::Runtime &runtime, jsi::Value &value)
{
rawProps = std::make_unique<RawProps>(runtime, value);
}
AnimatedProps get()
{
return AnimatedProps{std::move(props), std::move(rawProps)};
}
};
} // namespace facebook::react

View File

@@ -0,0 +1,176 @@
/*
* 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 "AnimationBackend.h"
#include <chrono>
namespace facebook::react {
static inline Props::Shared cloneProps(
AnimatedProps& animatedProps,
const ShadowNode& shadowNode) {
PropsParserContext propsParserContext{
shadowNode.getSurfaceId(), *shadowNode.getContextContainer()};
Props::Shared newProps;
if (animatedProps.rawProps) {
newProps = shadowNode.getComponentDescriptor().cloneProps(
propsParserContext,
shadowNode.getProps(),
std::move(*animatedProps.rawProps));
} else {
newProps = shadowNode.getComponentDescriptor().cloneProps(
propsParserContext, shadowNode.getProps(), {});
}
auto viewProps = std::const_pointer_cast<BaseViewProps>(
std::static_pointer_cast<const BaseViewProps>(newProps));
for (auto& animatedProp : animatedProps.props) {
switch (animatedProp->propName) {
case OPACITY:
viewProps->opacity = get<Float>(animatedProp);
break;
case WIDTH:
viewProps->yogaStyle.setDimension(
yoga::Dimension::Width, get<yoga::Style::SizeLength>(animatedProp));
break;
case HEIGHT:
viewProps->yogaStyle.setDimension(
yoga::Dimension::Height,
get<yoga::Style::SizeLength>(animatedProp));
break;
case BORDER_RADII:
viewProps->borderRadii = get<CascadedBorderRadii>(animatedProp);
break;
case FLEX:
viewProps->yogaStyle.setFlex(get<yoga::FloatOptional>(animatedProp));
break;
case TRANSFORM:
viewProps->transform = get<Transform>(animatedProp);
break;
}
}
return newProps;
}
static inline bool mutationHasLayoutUpdates(
facebook::react::AnimationMutation& mutation) {
for (auto& animatedProp : mutation.props.props) {
// TODO: there should also be a check for the dynamic part
if (animatedProp->propName == WIDTH || animatedProp->propName == HEIGHT ||
animatedProp->propName == FLEX) {
return true;
}
}
return false;
}
AnimationBackend::AnimationBackend(
StartOnRenderCallback&& startOnRenderCallback,
StopOnRenderCallback&& stopOnRenderCallback,
DirectManipulationCallback&& directManipulationCallback,
FabricCommitCallback&& fabricCommitCallback,
UIManager* uiManager)
: startOnRenderCallback_(std::move(startOnRenderCallback)),
stopOnRenderCallback_(std::move(stopOnRenderCallback)),
directManipulationCallback_(std::move(directManipulationCallback)),
fabricCommitCallback_(std::move(fabricCommitCallback)),
uiManager_(uiManager) {}
void AnimationBackend::onAnimationFrame(double timestamp) {
std::unordered_map<Tag, AnimatedProps> updates;
std::unordered_set<const ShadowNodeFamily*> families;
bool hasAnyLayoutUpdates = false;
for (auto& callback : callbacks) {
auto muatations = callback(static_cast<float>(timestamp));
for (auto& mutation : muatations) {
hasAnyLayoutUpdates |= mutationHasLayoutUpdates(mutation);
families.insert(mutation.family);
updates[mutation.tag] = std::move(mutation.props);
}
}
if (hasAnyLayoutUpdates) {
commitUpdatesWithFamilies(families, updates);
} else {
synchronouslyUpdateProps(updates);
}
}
void AnimationBackend::start(const Callback& callback, bool isAsync) {
callbacks.push_back(callback);
// TODO: startOnRenderCallback_ should provide the timestamp from the platform
startOnRenderCallback_(
[this]() {
onAnimationFrame(
std::chrono::steady_clock::now().time_since_epoch().count() / 1000);
},
isAsync);
}
void AnimationBackend::stop(bool isAsync) {
stopOnRenderCallback_(isAsync);
callbacks.clear();
}
void AnimationBackend::commitUpdatesWithFamilies(
const std::unordered_set<const ShadowNodeFamily*>& families,
std::unordered_map<Tag, AnimatedProps>& updates) {
uiManager_->getShadowTreeRegistry().enumerate(
[families, &updates](const ShadowTree& shadowTree, bool& /*stop*/) {
shadowTree.commit(
[families, &updates](const RootShadowNode& oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(
oldRootShadowNode.cloneMultiple(
families,
[families, &updates](
const ShadowNode& shadowNode,
const ShadowNodeFragment& fragment) {
auto& animatedProps = updates.at(shadowNode.getTag());
auto newProps = cloneProps(animatedProps, shadowNode);
return shadowNode.clone(
{newProps,
fragment.children,
shadowNode.getState()});
}));
},
{.mountSynchronously = true});
});
}
void AnimationBackend::synchronouslyUpdateProps(
const std::unordered_map<Tag, AnimatedProps>& 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<Float>(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);
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,59 @@
/*
* 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 <folly/dynamic.h>
#include <react/renderer/core/ReactPrimitives.h>
#include <react/renderer/uimanager/UIManager.h>
#include <react/renderer/uimanager/UIManagerAnimationBackend.h>
#include <functional>
#include <vector>
#include "AnimatedProps.h"
#include "AnimatedPropsBuilder.h"
namespace facebook::react {
struct AnimationMutation {
Tag tag;
const ShadowNodeFamily *family;
AnimatedProps props;
};
using AnimationMutations = std::vector<AnimationMutation>;
class AnimationBackend : public UIManagerAnimationBackend {
public:
using Callback = std::function<AnimationMutations(float)>;
using StartOnRenderCallback = std::function<void(std::function<void()> &&, bool /* isAsync */)>;
using StopOnRenderCallback = std::function<void(bool /* isAsync */)>;
using DirectManipulationCallback = std::function<void(Tag, const folly::dynamic &)>;
using FabricCommitCallback = std::function<void(std::unordered_map<Tag, folly::dynamic> &)>;
std::vector<Callback> callbacks;
const StartOnRenderCallback startOnRenderCallback_;
const StopOnRenderCallback stopOnRenderCallback_;
const DirectManipulationCallback directManipulationCallback_;
const FabricCommitCallback fabricCommitCallback_;
UIManager *uiManager_;
AnimationBackend(
StartOnRenderCallback &&startOnRenderCallback,
StopOnRenderCallback &&stopOnRenderCallback,
DirectManipulationCallback &&directManipulationCallback,
FabricCommitCallback &&fabricCommitCallback,
UIManager *uiManager);
void commitUpdatesWithFamilies(
const std::unordered_set<const ShadowNodeFamily *> &families,
std::unordered_map<Tag, AnimatedProps> &updates);
void synchronouslyUpdateProps(const std::unordered_map<Tag, AnimatedProps> &updates);
void onAnimationFrame(double timestamp) override;
void start(const Callback &callback, bool isAsync);
void stop(bool isAsync) override;
};
} // namespace facebook::react

View File

@@ -0,0 +1,28 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_renderer_animationbackend_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_renderer_animationbackend OBJECT ${react_renderer_animationbackend_SRC})
target_include_directories(react_renderer_animationbackend PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_renderer_animationbackend
react_codegen_rncore
react_debug
react_renderer_core
react_renderer_graphics
react_renderer_mounting
react_renderer_uimanager
react_renderer_scheduler
glog
folly_runtime
)
target_compile_reactnative_options(react_renderer_animationbackend PRIVATE)
target_compile_options(react_renderer_animationbackend PRIVATE -Wpedantic)