Skip to content
Merged
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 @@ -54,10 +54,7 @@ void AnimatedPropsRegistry::update(jsi::Runtime &rt, const jsi::Value &operation
}
}

jsi::Value AnimatedPropsRegistry::collectSettledUpdates(
jsi::Runtime &rt,
const double settledTimestamp,
std::vector<Tag> &evictedTags) {
jsi::Value AnimatedPropsRegistry::collectSettledUpdates(jsi::Runtime &rt, const double settledTimestamp) {
react_native_assert(UpdatesRegistryManager::isLockedByCurrentThread());

std::vector<std::pair<Tag, std::reference_wrapper<const folly::dynamic>>> updates;
Expand All @@ -73,7 +70,6 @@ jsi::Value AnimatedPropsRegistry::collectSettledUpdates(
// are disjoint — `update()` moves tags from the former to the latter.
timestampMap_.erase(viewTag);
it = updatesRegistry_.erase(it);
evictedTags.push_back(viewTag);
continue;
}

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

#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace reanimated {

Expand All @@ -19,7 +18,7 @@ class AnimatedPropsRegistry : public UpdatesRegistry {
/// Also evicts entries that have already been synced to React — by the time
/// of the next call, the corresponding `settledProps` state is guaranteed to
/// be committed, so the registry entries are redundant.
jsi::Value collectSettledUpdates(jsi::Runtime &rt, double settledTimestamp, std::vector<Tag> &evictedTags);
jsi::Value collectSettledUpdates(jsi::Runtime &rt, double settledTimestamp);

private:
std::unordered_map<Tag, double> timestampMap_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ PropsMap UpdatesRegistryManager::collectProps() {
return propsMap;
}

void UpdatesRegistryManager::addRegistryProps(PropsMap &propsMap) {
react_native_assert(isLockedByCurrentThread());
for (auto &[family, props] : propsMap) {
for (const auto &registry : registries_) {
auto registryProps = registry->get(family->getTag());
if (registryProps.isObject()) {
props.emplace_back(RawProps(std::move(registryProps)));
}
}
}
}

#ifdef ANDROID

bool UpdatesRegistryManager::hasPropsToRevert() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class UpdatesRegistryManager {
void unmarkNodeAsRemovable(Tag viewTag);
void handleNodeRemovals(const RootShadowNode &rootShadowNode);
PropsMap collectProps();
void addRegistryProps(PropsMap &propsMap);

#ifdef ANDROID
bool hasPropsToRevert();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ class LayoutAnimationsProxyCommon : public facebook::react::MountingOverrideDele
std::weak_ptr<const facebook::react::MountingOverrideDelegate> mountingOverrideDelegate);
virtual void shadowTreeWillCommit(bool isSurfaceRemoval) {}
virtual void surfaceDidUnmount();
virtual void applySynchronousProps(const UpdatesBatch &, const std::unordered_set<Tag> &) const {}
virtual void dropSynchronousProps(const std::vector<Tag> &) const {}
virtual void applySynchronousProps(const UpdatesBatch &) const {}
~LayoutAnimationsProxyCommon() override = default;

protected:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,9 @@ std::optional<SurfaceId> LayoutAnimationsProxyRegistry::onGestureCancel(const in
return {};
}

void LayoutAnimationsProxyRegistry::applySynchronousProps(
const UpdatesBatch &updatesBatch,
const std::unordered_set<Tag> &skipOverlayTags) {
void LayoutAnimationsProxyRegistry::applySynchronousProps(const UpdatesBatch &updatesBatch) {
for (const auto &instance : instances()) {
instance->applySynchronousProps(updatesBatch, skipOverlayTags);
}
}

void LayoutAnimationsProxyRegistry::dropSynchronousProps(const std::vector<Tag> &tags) {
for (const auto &instance : instances()) {
instance->dropSynchronousProps(tags);
instance->applySynchronousProps(updatesBatch);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <memory>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace reanimated {
Expand All @@ -26,8 +25,7 @@ class LayoutAnimationsProxyRegistry {
std::optional<SurfaceId> endLayoutAnimation(int tag, bool shouldRemove);
std::optional<SurfaceId> onTransitionProgress(int tag, double progress, bool isClosing, bool isGoingForward);
std::optional<SurfaceId> onGestureCancel(int tag);
void applySynchronousProps(const UpdatesBatch &updatesBatch, const std::unordered_set<Tag> &skipOverlayTags);
void dropSynchronousProps(const std::vector<Tag> &tags);
void applySynchronousProps(const UpdatesBatch &updatesBatch);

private:
std::vector<std::shared_ptr<LayoutAnimationsProxyCommon>> instances() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ void LayoutAnimationsProxy_Experimental::updateLightTree(
case ShadowViewMutation::Update: {
auto &node = lightNodes_[mutation.newChildShadowView.tag];
react_native_assert(node && "LightNode not found");
const auto currentProps = node->current.props;
node->previous = mutation.oldChildShadowView;
#ifdef ANDROID
// TODO (future): We don't merge the root view as the currently stored version might not be accurate, because of
Expand All @@ -266,8 +267,10 @@ void LayoutAnimationsProxy_Experimental::updateLightTree(
}
#else
node->current = mutation.newChildShadowView;
reapplySynchronousPropsOverlay(node, propsParserContext);
#endif // ANDROID
if (mutation.oldChildShadowView.props == mutation.newChildShadowView.props) {
node->current.props = currentProps;
}
auto tag = mutation.newChildShadowView.tag;
if (layoutAnimationsManager_->hasLayoutAnimation(tag, LAYOUT)) {
layout_.push_back(node);
Expand All @@ -294,9 +297,6 @@ void LayoutAnimationsProxy_Experimental::updateLightTree(
if (state == UNDEFINED) {
lightNodes_.erase(it);
}
#ifndef ANDROID
synchronousPropsOverlay_.erase(mutation.oldChildShadowView.tag);
#endif
break;
}
case ShadowViewMutation::Insert: {
Expand Down Expand Up @@ -413,18 +413,10 @@ void LayoutAnimationsProxy_Experimental::applyInitialMutationsToLightTree(
// Synchronous prop updates skip pullTransaction. Merge them into the light
// tree so shared-transition snapshots see them. The registry broadcasts one
// batch to every surface proxy; entries of other surfaces are skipped here.
void LayoutAnimationsProxy_Experimental::applySynchronousProps(
const UpdatesBatch &updatesBatch,
[[maybe_unused]] const std::unordered_set<Tag> &skipOverlayTags) const {
void LayoutAnimationsProxy_Experimental::applySynchronousProps(const UpdatesBatch &updatesBatch) const {
ReanimatedSystraceSection s("applySynchronousProps");
const auto lock = std::unique_lock<std::recursive_mutex>(mutex);

#ifndef ANDROID
for (const auto tag : skipOverlayTags) {
synchronousPropsOverlay_.erase(tag);
}
#endif

for (const auto &[shadowNodeFamily, props] : updatesBatch) {
if (shadowNodeFamily->getSurfaceId() != surfaceId_) {
continue;
Expand All @@ -445,44 +437,13 @@ void LayoutAnimationsProxy_Experimental::applySynchronousProps(
auto rawProps = props;
#ifdef RN_SERIALIZABLE_STATE
rawProps = folly::dynamic::merge(node->current.props->rawProps, rawProps);
#endif
#ifndef ANDROID
if (!skipOverlayTags.contains(node->current.tag)) {
auto &overlayProps = synchronousPropsOverlay_[node->current.tag];
overlayProps = overlayProps.isObject() ? folly::dynamic::merge(overlayProps, props) : props;
}
#endif
const PropsParserContext propsParserContext{node->current.surfaceId, *contextContainer_};
node->current.props = getComponentDescriptorForShadowView(node->current)
.cloneProps(propsParserContext, node->current.props, RawProps(std::move(rawProps)));
}
}

#ifndef ANDROID
// A commit that does not carry the synchronous props replaces the light tree
// props in the Update branch. Put the synchronous props back on top. The
// entry lives until the settled sync-back commits the values to React state.
void LayoutAnimationsProxy_Experimental::reapplySynchronousPropsOverlay(
const std::shared_ptr<LightNode> &node,
const PropsParserContext &propsParserContext) const {
const auto it = synchronousPropsOverlay_.find(node->current.tag);
if (it == synchronousPropsOverlay_.end() || !node->current.props) {
return;
}
node->current.props = getComponentDescriptorForShadowView(node->current)
.cloneProps(propsParserContext, node->current.props, RawProps(it->second));
}
#endif // ANDROID

void LayoutAnimationsProxy_Experimental::dropSynchronousProps([[maybe_unused]] const std::vector<Tag> &tags) const {
#ifndef ANDROID
const auto lock = std::unique_lock<std::recursive_mutex>(mutex);
for (const auto tag : tags) {
synchronousPropsOverlay_.erase(tag);
}
#endif
}

void LayoutAnimationsProxy_Experimental::startSurface(
const ShadowTree &shadowTree,
std::weak_ptr<const MountingOverrideDelegate> mountingOverrideDelegate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ struct LayoutAnimationsProxy_Experimental : public LayoutAnimationsProxyCommon,
mutable std::vector<std::pair<ShadowTreeRevision::Number, ShadowViewMutationList>> pendingTransactions_;
mutable std::vector<std::shared_ptr<LightNode>> containersToInsert_;
mutable std::unordered_map<Tag, react::Transform> transformForNode_;
#ifndef ANDROID
mutable std::unordered_map<Tag, folly::dynamic> synchronousPropsOverlay_;
#endif

mutable ForceScreenSnapshotFunction forceScreenSnapshot_;

Expand Down Expand Up @@ -89,14 +86,7 @@ struct LayoutAnimationsProxy_Experimental : public LayoutAnimationsProxyCommon,
return lightNodes_.contains(surfaceId_);
}

void applySynchronousProps(const UpdatesBatch &updatesBatch, const std::unordered_set<Tag> &skipOverlayTags)
const override;
void dropSynchronousProps(const std::vector<Tag> &tags) const override;
#ifndef ANDROID
void reapplySynchronousPropsOverlay(
const std::shared_ptr<LightNode> &node,
const PropsParserContext &propsParserContext) const;
#endif
void applySynchronousProps(const UpdatesBatch &updatesBatch) const override;

void reconcileContradictedRemovals(const ShadowViewMutationList &mutations, ShadowViewMutationList &filteredMutations)
const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,18 +674,8 @@ jsi::Value ReanimatedModuleProxy::getSettledUpdates(jsi::Runtime &rt) {
const auto currentTimestamp = getAnimationTimestamp_();

// TODO(future): flush updates from CSS animations and CSS transitions registries
std::vector<Tag> evictedTags;
auto lock = updatesRegistryManager_->lock();
auto settledUpdates =
animatedPropsRegistry_->collectSettledUpdates(rt, currentTimestamp - SETTLED_ANIMATION_THRESHOLD_MS, evictedTags);

if constexpr (StaticFeatureFlags::getFlag("ENABLE_SHARED_ELEMENT_TRANSITIONS")) {
if (layoutAnimationsProxyRegistry_ && !evictedTags.empty()) {
layoutAnimationsProxyRegistry_->dropSynchronousProps(evictedTags);
}
}

return settledUpdates;
return animatedPropsRegistry_->collectSettledUpdates(rt, currentTimestamp - SETTLED_ANIMATION_THRESHOLD_MS);
}

bool ReanimatedModuleProxy::handleEvent(
Expand Down Expand Up @@ -809,19 +799,6 @@ void ReanimatedModuleProxy::performOperations() {
jsi::Runtime &uiRuntime = getJSIRuntimeFromWorkletRuntime(uiRuntime_);

UpdatesBatch updatesBatch;
// The settled-props sync-back manages only animated props, so updates
// flushed by the CSS registries must stay out of the synchronous props
// overlay of the layout animations proxy.
std::unordered_set<Tag> skipOverlayTags;
const auto collectFlushedTags = [&](const size_t begin) {
if constexpr (
shouldUseSynchronousUpdatesInPerformOperations() &&
StaticFeatureFlags::getFlag("ENABLE_SHARED_ELEMENT_TRANSITIONS")) {
for (auto i = begin; i < updatesBatch.size(); ++i) {
skipOverlayTags.insert(updatesBatch[i].first->getTag());
}
}
};
{
ReanimatedSystraceSection s2("ReanimatedModuleProxy::flushUpdates");

Expand All @@ -830,22 +807,19 @@ void ReanimatedModuleProxy::performOperations() {
if (cssTransitionsRegistry_->needsFlush()) {
// Update CSS transitions and flush updates
cssTransitionsRegistry_->flushUpdates(updatesBatch);
collectFlushedTags(0);
}

// Flush all animated props updates
animatedPropsRegistry_->flushUpdates(updatesBatch);

if (cssAnimationsRegistry_->needsFlush()) {
// Update CSS animations and flush updates
const auto begin = updatesBatch.size();
cssAnimationsRegistry_->flushUpdates(updatesBatch);
collectFlushedTags(begin);
}
}

if constexpr (shouldUseSynchronousUpdatesInPerformOperations()) {
applySynchronousUpdates(updatesBatch, false, skipOverlayTags);
applySynchronousUpdates(updatesBatch, false);
}

if (updatesRegistryManager_->shouldReanimatedSkipCommit()) {
Expand All @@ -871,7 +845,7 @@ void ReanimatedModuleProxy::performNonLayoutOperations() {
auto lock = updatesRegistryManager_->lock();
updatesBatch = animatedPropsRegistry_->getPendingUpdates();
}
applySynchronousUpdates(updatesBatch, true, {});
applySynchronousUpdates(updatesBatch, true);
}

#if REACT_NATIVE_VERSION_MINOR >= 85
Expand Down Expand Up @@ -1054,16 +1028,13 @@ bool ReanimatedModuleProxy::handleEventAndFlush(
return handled;
}

void ReanimatedModuleProxy::applySynchronousUpdates(
UpdatesBatch &updatesBatch,
const bool allowPartialUpdates,
const std::unordered_set<Tag> &skipOverlayTags) {
void ReanimatedModuleProxy::applySynchronousUpdates(UpdatesBatch &updatesBatch, const bool allowPartialUpdates) {
auto [synchronousUpdatesBatch, shadowTreeUpdatesBatch] =
partitionUpdates(std::move(updatesBatch), allowPartialUpdates);

if constexpr (StaticFeatureFlags::getFlag("ENABLE_SHARED_ELEMENT_TRANSITIONS")) {
if (layoutAnimationsProxyRegistry_ && (!synchronousUpdatesBatch.empty() || !skipOverlayTags.empty())) {
layoutAnimationsProxyRegistry_->applySynchronousProps(synchronousUpdatesBatch, skipOverlayTags);
if (layoutAnimationsProxyRegistry_ && !synchronousUpdatesBatch.empty()) {
layoutAnimationsProxyRegistry_->applySynchronousProps(synchronousUpdatesBatch);
}
}

Expand Down Expand Up @@ -1129,6 +1100,12 @@ void ReanimatedModuleProxy::commitUpdates(jsi::Runtime &rt, const UpdatesBatch &
for (auto const &[shadowNodeFamily, props] : updatesBatch) {
propsMapBySurface[shadowNodeFamily->getSurfaceId()][shadowNodeFamily].emplace_back(props);
}
if constexpr (shouldUseSynchronousUpdatesInPerformOperations()) {
auto lock = updatesRegistryManager_->lock();
for (auto &[_, propsMap] : propsMapBySurface) {
updatesRegistryManager_->addRegistryProps(propsMap);
}
}
}

for (auto const &[surfaceId, propsMap] : propsMapBySurface) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include <mutex>
#include <set>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -207,10 +206,7 @@ class ReanimatedModuleProxy : public std::enable_shared_from_this<ReanimatedModu
std::function<std::string()> createRegistriesLeakCheck();

void commitUpdates(jsi::Runtime &rt, const UpdatesBatch &updatesBatch);
void applySynchronousUpdates(
UpdatesBatch &updatesBatch,
bool allowPartialUpdates,
const std::unordered_set<Tag> &skipOverlayTags);
void applySynchronousUpdates(UpdatesBatch &updatesBatch, bool allowPartialUpdates);

#if REACT_NATIVE_VERSION_MINOR >= 85
std::shared_ptr<UIManagerAnimationBackend> getAnimationBackend();
Expand Down
Loading