Skip to content

Commit 408478c

Browse files
zeyapmeta-codesync[bot]
authored andcommitted
Add bitmap snapshot capture/display delegate plumbing (#56458)
Summary: Pull Request resolved: #56458 ## Changelog: [Internal] [Added] - Add bitmap snapshot capture/display delegate plumbing Wire view transition bitmap snapshot capture and display through the C++ delegate chain so platforms can implement snapshotting old-element views. **ViewTransitionModule.cpp**: Call `uiManagerDidCaptureViewSnapshot(tag, surfaceId)` in `applyViewTransitionName` to capture a bitmap of the old view while it is still mounted, and `uiManagerDidSetViewSnapshot(sourceTag, targetTag, surfaceId)` in `applySnapshotsOnPseudoElementShadowNodes` to map captured bitmaps onto pseudo-element views. **UIManagerDelegate / SchedulerDelegate**: Add pure virtual `captureViewSnapshot` and `setViewSnapshot` methods. **Scheduler**: Forward `UIManagerDelegate` calls to `SchedulerDelegate`. **Platform stubs**: Empty implementations for iOS (`RCTScheduler.mm`), CxxPlatform (`SchedulerDelegateImpl`), and Android JNI (`FabricUIManagerBinding`) — Android implementation follows in D99173446. Reviewed By: NickGerleman Differential Revision: D98354659
1 parent 3695019 commit 408478c

16 files changed

Lines changed: 222 additions & 8 deletions

File tree

packages/react-native/React/Fabric/RCTScheduler.mm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,24 @@ void schedulerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic>
8585
// This delegate method is not currently used on iOS.
8686
}
8787

88+
void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override
89+
{
90+
// Does nothing.
91+
// View transition snapshots are not currently implemented on iOS.
92+
}
93+
94+
void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override
95+
{
96+
// Does nothing.
97+
// View transition snapshots are not currently implemented on iOS.
98+
}
99+
100+
void schedulerDidClearPendingSnapshots() override
101+
{
102+
// Does nothing.
103+
// View transition snapshots are not currently implemented on iOS.
104+
}
105+
88106
private:
89107
void *scheduler_;
90108
};

packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,23 @@ void FabricUIManagerBinding::schedulerDidUpdateShadowTree(
797797
// no-op
798798
}
799799

800+
void FabricUIManagerBinding::schedulerDidCaptureViewSnapshot(
801+
Tag tag,
802+
SurfaceId surfaceId) {
803+
// TODO: implement this
804+
}
805+
806+
void FabricUIManagerBinding::schedulerDidSetViewSnapshot(
807+
Tag sourceTag,
808+
Tag targetTag,
809+
SurfaceId surfaceId) {
810+
// TODO: implement this
811+
}
812+
813+
void FabricUIManagerBinding::schedulerDidClearPendingSnapshots() {
814+
// TODO: implement this
815+
}
816+
800817
void FabricUIManagerBinding::onAnimationStarted() {
801818
auto mountingManager = getMountingManager("onAnimationStarted");
802819
if (!mountingManager) {

packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ class FabricUIManagerBinding : public jni::HybridClass<FabricUIManagerBinding>,
117117

118118
void schedulerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic> &tagToProps) override;
119119

120+
void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override;
121+
122+
void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override;
123+
124+
void schedulerDidClearPendingSnapshots() override;
125+
120126
void setPixelDensity(float pointScaleFactor);
121127

122128
void driveCxxAnimations();

packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,27 @@ void Scheduler::uiManagerDidUpdateShadowTree(
364364
}
365365
}
366366

367+
void Scheduler::uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) {
368+
if (delegate_ != nullptr) {
369+
delegate_->schedulerDidCaptureViewSnapshot(tag, surfaceId);
370+
}
371+
}
372+
373+
void Scheduler::uiManagerDidSetViewSnapshot(
374+
Tag sourceTag,
375+
Tag targetTag,
376+
SurfaceId surfaceId) {
377+
if (delegate_ != nullptr) {
378+
delegate_->schedulerDidSetViewSnapshot(sourceTag, targetTag, surfaceId);
379+
}
380+
}
381+
382+
void Scheduler::uiManagerDidClearPendingSnapshots() {
383+
if (delegate_ != nullptr) {
384+
delegate_->schedulerDidClearPendingSnapshots();
385+
}
386+
}
387+
367388
void Scheduler::uiManagerShouldAddEventListener(
368389
std::shared_ptr<const EventListener> listener) {
369390
addEventListener(listener);

packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class Scheduler final : public UIManagerDelegate {
9494
bool blockNativeResponder) override;
9595
void uiManagerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) override;
9696
void uiManagerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic> &tagToProps) override;
97+
void uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override;
98+
void uiManagerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override;
99+
void uiManagerDidClearPendingSnapshots() override;
97100
void uiManagerShouldAddEventListener(std::shared_ptr<const EventListener> listener) final;
98101
void uiManagerShouldRemoveEventListener(const std::shared_ptr<const EventListener> &listener) final;
99102
void uiManagerDidFinishReactCommit(const ShadowTree &shadowTree) override;

packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ class SchedulerDelegate {
6666

6767
virtual void schedulerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic> &tagToProps) = 0;
6868

69+
// View transition bitmap snapshot capture and application.
70+
virtual void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) = 0;
71+
virtual void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) = 0;
72+
virtual void schedulerDidClearPendingSnapshots() = 0;
73+
6974
virtual ~SchedulerDelegate() noexcept = default;
7075
};
7176

packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ class UIManagerDelegate {
9797
using OnSurfaceStartCallback = std::function<void(const ShadowTree &shadowTree)>;
9898
virtual void uiManagerShouldSetOnSurfaceStartCallback(OnSurfaceStartCallback &&callback) = 0;
9999

100+
// View transition bitmap snapshot capture and application.
101+
virtual void uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) = 0;
102+
virtual void uiManagerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) = 0;
103+
virtual void uiManagerDidClearPendingSnapshots() = 0;
104+
100105
virtual ~UIManagerDelegate() noexcept = default;
101106
};
102107

packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,14 @@ void ViewTransitionModule::applyViewTransitionName(
8282
.layoutMetrics = keyframeMetrics, .tag = tag, .surfaceId = surfaceId};
8383
oldLayout_[name] = oldView;
8484

85-
// TODO: capture bitmap snapshot of old view via platform
85+
// Request the platform to capture a bitmap snapshot of the old view
86+
// while it's still mounted. The platform stores the bitmap keyed by tag.
87+
if (uiManager_ != nullptr) {
88+
auto* delegate = uiManager_->getDelegate();
89+
if (delegate != nullptr) {
90+
delegate->uiManagerDidCaptureViewSnapshot(tag, surfaceId);
91+
}
92+
}
8693

8794
if (auto it = oldPseudoElementNodesRepository_.find(name);
8895
it != oldPseudoElementNodesRepository_.end()) {
@@ -277,7 +284,18 @@ void ViewTransitionModule::applySnapshotsOnPseudoElementShadowNodes() {
277284
return;
278285
}
279286

280-
// TODO: set bitmap snapshots on pseudo-element views via platform
287+
// Set view snapshots — the pseudo-element nodes themselves will be committed
288+
// through the normal completeRoot flow via getPseudoElementNodes().
289+
auto* delegate = uiManager_->getDelegate();
290+
if (delegate != nullptr) {
291+
for (const auto& [name, node] : oldPseudoElementNodes_) {
292+
auto layoutIt = oldLayout_.find(name);
293+
if (layoutIt != oldLayout_.end()) {
294+
delegate->uiManagerDidSetViewSnapshot(
295+
layoutIt->second.tag, node->getTag(), node->getSurfaceId());
296+
}
297+
}
298+
}
281299
}
282300

283301
LayoutMetrics ViewTransitionModule::captureLayoutMetricsFromRoot(
@@ -343,6 +361,14 @@ void ViewTransitionModule::startViewTransitionEnd() {
343361
nameRegistry_.clear();
344362
oldPseudoElementNodes_.clear();
345363

364+
// Clear any pending bitmap snapshots that were captured but never consumed.
365+
if (uiManager_ != nullptr) {
366+
auto* delegate = uiManager_->getDelegate();
367+
if (delegate != nullptr) {
368+
delegate->uiManagerDidClearPendingSnapshots();
369+
}
370+
}
371+
346372
transitionStarted_ = false;
347373
}
348374

packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,15 @@ void SchedulerDelegateImpl::schedulerDidUpdateShadowTree(
7676
mountingManager_->onUpdateShadowTree(tagToProps);
7777
}
7878

79+
void SchedulerDelegateImpl::schedulerDidCaptureViewSnapshot(
80+
Tag /*tag*/,
81+
SurfaceId /*surfaceId*/) {}
82+
83+
void SchedulerDelegateImpl::schedulerDidSetViewSnapshot(
84+
Tag /*sourceTag*/,
85+
Tag /*targetTag*/,
86+
SurfaceId /*surfaceId*/) {}
87+
88+
void SchedulerDelegateImpl::schedulerDidClearPendingSnapshots() {}
89+
7990
} // namespace facebook::react

packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ class SchedulerDelegateImpl : public SchedulerDelegate {
5151

5252
void schedulerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic> &tagToProps) override;
5353

54+
void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override;
55+
56+
void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override;
57+
58+
void schedulerDidClearPendingSnapshots() override;
59+
5460
std::shared_ptr<IMountingManager> mountingManager_;
5561
std::shared_ptr<UIManager> uiManager_;
5662
};

0 commit comments

Comments
 (0)