mirror of
https://github.com/status-im/react-native.git
synced 2025-01-19 14:02:10 +00:00
eabf29e320
Summary: @public After reading about move-semantic and rvalue refs I realized that we (I) definitely overuse `auto &&` (aka universal reference) construction. Even if this is harmless, does not look good and idiomatic. Whenever I used that from a semantical point of view I always meant "I need an alias for this" which is actually "read-only reference" which is `const auto &`. This is also fit good to our policy where "everything is const (immutable) by default". Hence I change that to how it should be. Reviewed By: fkgozali Differential Revision: D8475637 fbshipit-source-id: 0a691ededa0e798db8ffa053bff0f400913ab7b8
153 lines
5.0 KiB
C++
153 lines
5.0 KiB
C++
// Copyright (c) 2004-present, Facebook, Inc.
|
|
|
|
// This source code is licensed under the MIT license found in the
|
|
// LICENSE file in the root directory of this source tree.
|
|
|
|
#include "ShadowTree.h"
|
|
|
|
#include <fabric/core/LayoutContext.h>
|
|
#include <fabric/core/LayoutPrimitives.h>
|
|
|
|
#include "ShadowTreeDelegate.h"
|
|
#include "Differentiator.h"
|
|
#include "TreeMutationInstruction.h"
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
ShadowTree::ShadowTree(Tag rootTag):
|
|
rootTag_(rootTag) {
|
|
|
|
const auto &noopEventEmitter = std::make_shared<const ViewEventEmitter>(nullptr, rootTag, nullptr);
|
|
rootShadowNode_ = std::make_shared<RootShadowNode>(
|
|
rootTag,
|
|
rootTag,
|
|
RootShadowNode::defaultSharedProps(),
|
|
noopEventEmitter,
|
|
ShadowNode::emptySharedShadowNodeSharedList(),
|
|
nullptr
|
|
);
|
|
}
|
|
|
|
Tag ShadowTree::getRootTag() const {
|
|
return rootTag_;
|
|
}
|
|
|
|
#pragma mark - Layout
|
|
|
|
Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
|
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
|
|
newRootShadowNode->layout();
|
|
return newRootShadowNode->getLayoutMetrics().frame.size;
|
|
}
|
|
|
|
void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
|
|
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
|
|
complete(newRootShadowNode);
|
|
}
|
|
|
|
#pragma mark - Commiting
|
|
|
|
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
|
auto oldRootShadowNode = rootShadowNode_;
|
|
const auto &props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
|
|
auto newRootShadowNode = std::make_shared<RootShadowNode>(oldRootShadowNode, props, nullptr, nullptr);
|
|
return newRootShadowNode;
|
|
}
|
|
|
|
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
|
|
auto oldRootShadowNode = rootShadowNode_;
|
|
auto newRootShadowNode =
|
|
std::make_shared<RootShadowNode>(oldRootShadowNode, nullptr, nullptr, SharedShadowNodeSharedList(rootChildNodes));
|
|
|
|
complete(newRootShadowNode);
|
|
}
|
|
|
|
void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
|
|
SharedRootShadowNode oldRootShadowNode = rootShadowNode_;
|
|
|
|
newRootShadowNode->layout();
|
|
|
|
newRootShadowNode->sealRecursive();
|
|
|
|
TreeMutationInstructionList instructions = TreeMutationInstructionList();
|
|
|
|
calculateMutationInstructions(
|
|
instructions,
|
|
oldRootShadowNode,
|
|
newRootShadowNode
|
|
);
|
|
|
|
if (commit(newRootShadowNode)) {
|
|
emitLayoutEvents(instructions);
|
|
|
|
if (delegate_) {
|
|
delegate_->shadowTreeDidCommit(shared_from_this(), instructions);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ShadowTree::commit(const SharedRootShadowNode &newRootShadowNode) {
|
|
std::lock_guard<std::mutex> lock(commitMutex_);
|
|
|
|
if (newRootShadowNode->getSourceNode() != rootShadowNode_) {
|
|
return false;
|
|
}
|
|
|
|
rootShadowNode_ = newRootShadowNode;
|
|
return true;
|
|
}
|
|
|
|
void ShadowTree::emitLayoutEvents(const TreeMutationInstructionList &instructions) {
|
|
for (const auto &instruction : instructions) {
|
|
const auto &type = instruction.getType();
|
|
|
|
// Only `Insertion` and `Replacement` instructions can affect layout metrics.
|
|
if (
|
|
type == TreeMutationInstruction::Insertion ||
|
|
type == TreeMutationInstruction::Replacement
|
|
) {
|
|
const auto &newShadowNode = instruction.getNewChildNode();
|
|
const auto &eventEmitter = newShadowNode->getEventEmitter();
|
|
const auto &viewEventEmitter = std::dynamic_pointer_cast<const ViewEventEmitter>(eventEmitter);
|
|
|
|
// Checking if particular shadow node supports `onLayout` event (part of `ViewEventEmitter`).
|
|
if (viewEventEmitter) {
|
|
// Now we know that both (old and new) shadow nodes must be `LayoutableShadowNode` subclasses.
|
|
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode));
|
|
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
|
|
const auto &newLayoutableShadowNode =
|
|
std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
|
|
|
|
// In case if we have `oldShadowNode`, we have to check that layout metrics have changed.
|
|
if (type == TreeMutationInstruction::Replacement) {
|
|
const auto &oldShadowNode = instruction.getOldChildNode();
|
|
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode));
|
|
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
|
|
const auto &oldLayoutableShadowNode =
|
|
std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode);
|
|
|
|
if (oldLayoutableShadowNode->getLayoutMetrics() == newLayoutableShadowNode->getLayoutMetrics()) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
viewEventEmitter->onLayout(newLayoutableShadowNode->getLayoutMetrics());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - Delegate
|
|
|
|
void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) {
|
|
delegate_ = delegate;
|
|
}
|
|
|
|
ShadowTreeDelegate *ShadowTree::getDelegate() const {
|
|
return delegate_;
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|