Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,17 @@ NativeAnimatedNodesManager::ensureEventEmitterListener() noexcept {
}

void NativeAnimatedNodesManager::startRenderCallbackIfNeeded(bool isAsync) {
// This method can be called from either the UI thread or JavaScript thread.
// It ensures `startOnRenderCallback_` is called exactly once using atomic
// operations. We use std::atomic_bool rather than std::mutex to avoid
// potential deadlocks that could occur if we called external code while
// holding a mutex.
auto isRenderCallbackStarted = isRenderCallbackStarted_.exchange(true);
if (isRenderCallbackStarted) {
// onRender callback is already started.
return;
}

if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
#ifdef RN_USE_ANIMATION_BACKEND
if (auto animationBackend = animationBackend_.lock()) {
Expand All @@ -531,16 +542,6 @@ void NativeAnimatedNodesManager::startRenderCallbackIfNeeded(bool isAsync) {

return;
}
// This method can be called from either the UI thread or JavaScript thread.
// It ensures `startOnRenderCallback_` is called exactly once using atomic
// operations. We use std::atomic_bool rather than std::mutex to avoid
// potential deadlocks that could occur if we called external code while
// holding a mutex.
auto isRenderCallbackStarted = isRenderCallbackStarted_.exchange(true);
if (isRenderCallbackStarted) {
// onRender callback is already started.
return;
}

if (startOnRenderCallback_) {
startOnRenderCallback_([this]() { onRender(); }, isAsync);
Expand All @@ -549,18 +550,21 @@ void NativeAnimatedNodesManager::startRenderCallbackIfNeeded(bool isAsync) {

void NativeAnimatedNodesManager::stopRenderCallbackIfNeeded(
bool isAsync) noexcept {
if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
if (auto animationBackend = animationBackend_.lock()) {
animationBackend->stop(isAsync);
}
return;
}
// When multiple threads reach this point, only one thread should call
// stopOnRenderCallback_. This synchronization is primarily needed during
// destruction of NativeAnimatedNodesManager. In normal operation,
// stopRenderCallbackIfNeeded is always called from the UI thread.
auto isRenderCallbackStarted = isRenderCallbackStarted_.exchange(false);

if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
if (isRenderCallbackStarted) {
if (auto animationBackend = animationBackend_.lock()) {
animationBackend->stop(isAsync);
}
}
return;
}

if (isRenderCallbackStarted) {
if (stopOnRenderCallback_) {
stopOnRenderCallback_(isAsync);
Expand Down Expand Up @@ -988,6 +992,7 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
AnimationMutation{tag, nullptr, propsBuilder.get()});
containsChange = true;
}
updateViewPropsDirect_.clear();
}

if (!containsChange) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,27 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
std::move(directManipulationCallback),
std::move(fabricCommitCallback),
uiManager);
#endif

nativeAnimatedNodesManager_ =
std::make_shared<NativeAnimatedNodesManager>(animationBackend_);

nativeAnimatedDelegate_ =
std::make_shared<UIManagerNativeAnimatedDelegateBackendImpl>(
animationBackend_);

uiManager->unstable_setAnimationBackend(animationBackend_);
#endif
} else {
nativeAnimatedNodesManager_ =
std::make_shared<NativeAnimatedNodesManager>(
std::move(directManipulationCallback),
std::move(fabricCommitCallback),
std::move(startOnRenderCallback_),
std::move(stopOnRenderCallback_));

nativeAnimatedDelegate_ =
std::make_shared<UIManagerNativeAnimatedDelegateImpl>(
nativeAnimatedNodesManager_);
}

addEventEmitterListener(
Expand All @@ -117,10 +125,6 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
return false;
}));

nativeAnimatedDelegate_ =
std::make_shared<UIManagerNativeAnimatedDelegateImpl>(
nativeAnimatedNodesManager_);

uiManager->setNativeAnimatedDelegate(nativeAnimatedDelegate_);

// TODO: remove force casting.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@

namespace facebook::react {

UIManagerNativeAnimatedDelegateBackendImpl::
UIManagerNativeAnimatedDelegateBackendImpl(
std::weak_ptr<UIManagerAnimationBackend> animationBackend)
: animationBackend_(std::move(animationBackend)) {}

void UIManagerNativeAnimatedDelegateBackendImpl::runAnimationFrame() {
if (auto animationBackendStrong = animationBackend_.lock()) {
animationBackendStrong->onAnimationFrame(
std::chrono::steady_clock::now().time_since_epoch().count() / 1000);
}
}

static inline Props::Shared cloneProps(
AnimatedProps& animatedProps,
const ShadowNode& shadowNode) {
Expand Down Expand Up @@ -108,15 +120,20 @@ void AnimationBackend::onAnimationFrame(double timestamp) {
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);
if (startOnRenderCallback_) {
startOnRenderCallback_(
[this]() {
onAnimationFrame(
std::chrono::steady_clock::now().time_since_epoch().count() /
1000);
},
isAsync);
}
}
void AnimationBackend::stop(bool isAsync) {
stopOnRenderCallback_(isAsync);
if (stopOnRenderCallback_) {
stopOnRenderCallback_(isAsync);
}
callbacks.clear();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@

namespace facebook::react {

class AnimationBackend;

class UIManagerNativeAnimatedDelegateBackendImpl : public UIManagerNativeAnimatedDelegate {
public:
explicit UIManagerNativeAnimatedDelegateBackendImpl(std::weak_ptr<UIManagerAnimationBackend> animationBackend);

void runAnimationFrame() override;

private:
std::weak_ptr<UIManagerAnimationBackend> animationBackend_;
};

struct AnimationMutation {
Tag tag;
const ShadowNodeFamily *family;
Expand Down
Loading