mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
336876509c
Summary: This is a core part of the Timeline feature (aka Time Travel Debugger). With these new primitives, any external library can initiate "saving" all the previous interface changes (commits) and unwind to any previous one (in order to introspect and validate visual side-effects). The next diff in the stack will implement UI for this feature integrated into Debug menu on iOS. Changelog: [Internal] Fabric-specific internal change. Reviewed By: sammy-SC Differential Revision: D25926660 fbshipit-source-id: 2e5f6892351d3053db8f64c1cf6ff445b0867ad7
121 lines
2.9 KiB
C++
121 lines
2.9 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "Timeline.h"
|
|
|
|
#include <react/renderer/uimanager/UIManager.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
Timeline::Timeline(ShadowTree const &shadowTree) : shadowTree_(&shadowTree) {
|
|
record(shadowTree.getCurrentRevision().rootShadowNode);
|
|
};
|
|
|
|
#pragma mark - Public
|
|
|
|
SurfaceId Timeline::getSurfaceId() const noexcept {
|
|
return shadowTree_->getSurfaceId();
|
|
}
|
|
|
|
void Timeline::pause() const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
assert(!paused_ && "");
|
|
paused_ = true;
|
|
}
|
|
|
|
void Timeline::resume() const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
|
|
if (snapshots_.size() > 0) {
|
|
rewind(snapshots_.at(snapshots_.size() - 1));
|
|
}
|
|
|
|
assert(paused_ && "");
|
|
paused_ = false;
|
|
}
|
|
|
|
bool Timeline::isPaused() const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
return paused_;
|
|
}
|
|
|
|
TimelineFrame::List Timeline::getFrames() const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
|
|
auto frames = TimelineFrame::List{};
|
|
frames.reserve(snapshots_.size());
|
|
for (auto const &snapshot : snapshots_) {
|
|
frames.push_back(snapshot.getFrame());
|
|
}
|
|
return frames;
|
|
}
|
|
|
|
TimelineFrame Timeline::getCurrentFrame() const noexcept {
|
|
assert(snapshots_.size() > currentSnapshotIndex_);
|
|
return snapshots_.at(currentSnapshotIndex_).getFrame();
|
|
}
|
|
|
|
void Timeline::rewind(TimelineFrame const &frame) const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
rewind(snapshots_.at(frame.getIndex()));
|
|
}
|
|
|
|
RootShadowNode::Unshared Timeline::shadowTreeWillCommit(
|
|
ShadowTree const &shadowTree,
|
|
RootShadowNode::Shared const &oldRootShadowNode,
|
|
RootShadowNode::Unshared const &newRootShadowNode) const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
|
|
if (rewinding_) {
|
|
return newRootShadowNode;
|
|
}
|
|
|
|
record(newRootShadowNode);
|
|
|
|
if (paused_) {
|
|
return nullptr;
|
|
}
|
|
|
|
return newRootShadowNode;
|
|
}
|
|
|
|
#pragma mark - Private & Internal
|
|
|
|
void Timeline::record(
|
|
RootShadowNode::Shared const &rootShadowNode) const noexcept {
|
|
auto index = (int)snapshots_.size();
|
|
snapshots_.push_back(TimelineSnapshot{rootShadowNode, index});
|
|
|
|
if (!paused_) {
|
|
currentSnapshotIndex_ = index;
|
|
}
|
|
}
|
|
|
|
void Timeline::rewind(TimelineSnapshot const &snapshot) const noexcept {
|
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
|
|
currentSnapshotIndex_ = snapshot.getFrame().getIndex();
|
|
|
|
assert(!rewinding_ && "");
|
|
rewinding_ = true;
|
|
|
|
auto rootShadowNode = snapshot.getRootShadowNode();
|
|
|
|
shadowTree_->commit(
|
|
[&](RootShadowNode const &oldRootShadowNode) -> RootShadowNode::Unshared {
|
|
return std::static_pointer_cast<RootShadowNode>(
|
|
rootShadowNode->ShadowNode::clone({}));
|
|
});
|
|
|
|
assert(rewinding_ && "");
|
|
rewinding_ = false;
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|