mirror of
https://github.com/status-im/react-native.git
synced 2025-01-30 19:25:11 +00:00
d94a9e2640
Summary: Given that fact that life-time of YGNode and ShadowNode objects must be idential and that we always allocate ShadowNode on heap, we can embed YGNode object right inside ShadowNode object and use pointer to it safely. That allows us to save additional memory allocation for every single layoutable shadow node! Whoo-hoo! Reviewed By: fkgozali Differential Revision: D8070121 fbshipit-source-id: 6eefbca1b7ac0a8aad235513b4c4899d414835f2
231 lines
7.2 KiB
C++
231 lines
7.2 KiB
C++
/**
|
|
* Copyright (c) 2015-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 "YogaLayoutableShadowNode.h"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
|
|
#include <fabric/core/LayoutContext.h>
|
|
#include <fabric/core/LayoutConstraints.h>
|
|
#include <fabric/debug/DebugStringConvertibleItem.h>
|
|
#include <fabric/view/conversions.h>
|
|
#include <yoga/Yoga.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
SharedYogaConfig YogaLayoutableShadowNode::suitableYogaConfig() {
|
|
static SharedYogaConfig sharedYogaConfig;
|
|
|
|
if (!sharedYogaConfig) {
|
|
sharedYogaConfig = std::shared_ptr<YGConfig>(YGConfigNew());
|
|
sharedYogaConfig->cloneNodeCallback = YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector;
|
|
}
|
|
|
|
return sharedYogaConfig;
|
|
}
|
|
|
|
YogaLayoutableShadowNode::YogaLayoutableShadowNode(
|
|
const SharedYogaStylableProps &props,
|
|
const SharedShadowNodeSharedList &children
|
|
):
|
|
yogaNode_({}) {
|
|
assert(props);
|
|
assert(children);
|
|
|
|
yogaNode_.setConfig(suitableYogaConfig().get());
|
|
yogaNode_.setStyle(props->yogaStyle);
|
|
yogaNode_.setContext(this);
|
|
yogaNode_.setDirty(true);
|
|
|
|
YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(&yogaNode_, children);
|
|
}
|
|
|
|
YogaLayoutableShadowNode::YogaLayoutableShadowNode(
|
|
const SharedYogaLayoutableShadowNode &shadowNode,
|
|
const SharedYogaStylableProps &props,
|
|
const SharedShadowNodeSharedList &children
|
|
):
|
|
yogaNode_(shadowNode->yogaNode_) {
|
|
yogaNode_.setConfig(suitableYogaConfig().get());
|
|
yogaNode_.setContext(this);
|
|
yogaNode_.setOwner(nullptr);
|
|
yogaNode_.setDirty(true);
|
|
|
|
if (props) {
|
|
yogaNode_.setStyle(props->yogaStyle);
|
|
}
|
|
|
|
if (children) {
|
|
YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(&yogaNode_, children);
|
|
}
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::cleanLayout() {
|
|
yogaNode_.setDirty(false);
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::dirtyLayout() {
|
|
yogaNode_.markDirtyAndPropogate();
|
|
}
|
|
|
|
bool YogaLayoutableShadowNode::getIsLayoutClean() const {
|
|
return !yogaNode_.isDirty();
|
|
}
|
|
|
|
bool YogaLayoutableShadowNode::getHasNewLayout() const {
|
|
return yogaNode_.getHasNewLayout();
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::setHasNewLayout(bool hasNewLayout) {
|
|
yogaNode_.setHasNewLayout(hasNewLayout);
|
|
}
|
|
|
|
#pragma mark - Mutating Methods
|
|
|
|
void YogaLayoutableShadowNode::enableMeasurement() {
|
|
ensureUnsealed();
|
|
|
|
yogaNode_.setMeasureFunc(YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector);
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child) {
|
|
ensureUnsealed();
|
|
|
|
auto yogaNodeRawPtr = &yogaNode_;
|
|
auto childYogaNodeRawPtr = &child->yogaNode_;
|
|
yogaNodeRawPtr->insertChild(childYogaNodeRawPtr, yogaNodeRawPtr->getChildrenCount());
|
|
|
|
if (childYogaNodeRawPtr->getOwner() == nullptr) {
|
|
child->ensureUnsealed();
|
|
childYogaNodeRawPtr->setOwner(yogaNodeRawPtr);
|
|
}
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) {
|
|
if (!getIsLayoutClean()) {
|
|
ensureUnsealed();
|
|
YGNodeCalculateLayout(&yogaNode_, YGUndefined, YGUndefined, YGDirectionInherit);
|
|
}
|
|
|
|
LayoutableShadowNode::layout(layoutContext);
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::layoutChildren(LayoutContext layoutContext) {
|
|
for (auto child : getLayoutableChildNodes()) {
|
|
auto yogaLayoutableChild = std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(child);
|
|
if (!yogaLayoutableChild) {
|
|
continue;
|
|
}
|
|
|
|
auto nonConstYogaLayoutableChild = std::const_pointer_cast<YogaLayoutableShadowNode>(yogaLayoutableChild);
|
|
|
|
LayoutMetrics childLayoutMetrics = layoutMetricsFromYogaNode(nonConstYogaLayoutableChild->yogaNode_);
|
|
nonConstYogaLayoutableChild->setLayoutMetrics(childLayoutMetrics);
|
|
}
|
|
}
|
|
|
|
#pragma mark - Yoga Connectors
|
|
|
|
YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex) {
|
|
// We have only raw pointer to the parent shadow node, but that's enough for now.
|
|
YogaLayoutableShadowNode *parentShadowNodeRawPtr = (YogaLayoutableShadowNode *)parentYogaNode->getContext();
|
|
assert(parentShadowNodeRawPtr);
|
|
|
|
// Old child shadow node already exists but we have only raw pointer to it...
|
|
YogaLayoutableShadowNode *oldShadowNodeRawPtr = (YogaLayoutableShadowNode *)oldYogaNode->getContext();
|
|
assert(oldShadowNodeRawPtr);
|
|
|
|
// ... but we have to address this by `shared_ptr`. We cannot create a new `shared_ptr` for it because we will end up with two shared pointers to
|
|
// single object which will cause preluminary destroyng the object.
|
|
// Another approaches to consider:
|
|
// * Create a new `shared_ptr` with empty deleter.
|
|
// * Using `childIndex` to find exact node.
|
|
SharedLayoutableShadowNode oldShadowNode = nullptr;
|
|
for (auto child : parentShadowNodeRawPtr->getLayoutableChildNodes()) {
|
|
if (child.get() == oldShadowNodeRawPtr) {
|
|
oldShadowNode = child;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(oldShadowNode);
|
|
|
|
// The new one does not exist yet. So, we have to clone and replace this using `cloneAndReplaceChild`.
|
|
SharedYogaLayoutableShadowNode newShadowNode =
|
|
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(parentShadowNodeRawPtr->cloneAndReplaceChild(oldShadowNode));
|
|
assert(newShadowNode);
|
|
|
|
return &newShadowNode->yogaNode_;
|
|
}
|
|
|
|
YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
|
|
YogaLayoutableShadowNode *shadowNodeRawPtr = (YogaLayoutableShadowNode *)yogaNode->getContext();
|
|
assert(shadowNodeRawPtr);
|
|
|
|
Size minimumSize = Size {0, 0};
|
|
Size maximumSize = Size {kFloatMax, kFloatMax};
|
|
|
|
switch (widthMode) {
|
|
case YGMeasureModeUndefined:
|
|
break;
|
|
case YGMeasureModeExactly:
|
|
minimumSize.width = fabricFloatFromYogaFloat(width);
|
|
maximumSize.width = fabricFloatFromYogaFloat(width);
|
|
break;
|
|
case YGMeasureModeAtMost:
|
|
maximumSize.width = fabricFloatFromYogaFloat(width);
|
|
break;
|
|
}
|
|
|
|
switch (heightMode) {
|
|
case YGMeasureModeUndefined:
|
|
break;
|
|
case YGMeasureModeExactly:
|
|
minimumSize.height = fabricFloatFromYogaFloat(height);
|
|
maximumSize.height = fabricFloatFromYogaFloat(height);
|
|
break;
|
|
case YGMeasureModeAtMost:
|
|
maximumSize.height = fabricFloatFromYogaFloat(height);
|
|
break;
|
|
}
|
|
|
|
Size size = shadowNodeRawPtr->measure(LayoutConstraints {minimumSize, maximumSize});
|
|
|
|
return YGSize {
|
|
yogaFloatFromFabricFloat(size.width),
|
|
yogaFloatFromFabricFloat(size.height)
|
|
};
|
|
}
|
|
|
|
void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNode *yogaNodeRawPtr, const SharedShadowNodeSharedList &children) {
|
|
auto yogaNodeChildren = YGVector();
|
|
|
|
for (const SharedShadowNode &shadowNode : *children) {
|
|
const SharedYogaLayoutableShadowNode yogaLayoutableShadowNode = std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(shadowNode);
|
|
|
|
if (!yogaLayoutableShadowNode) {
|
|
continue;
|
|
}
|
|
|
|
auto &&childYogaNodeRawPtr = &yogaLayoutableShadowNode->yogaNode_;
|
|
|
|
yogaNodeChildren.push_back(childYogaNodeRawPtr);
|
|
|
|
if (childYogaNodeRawPtr->getOwner() == nullptr) {
|
|
yogaLayoutableShadowNode->ensureUnsealed();
|
|
childYogaNodeRawPtr->setOwner(yogaNodeRawPtr);
|
|
}
|
|
}
|
|
|
|
yogaNodeRawPtr->setChildren(yogaNodeChildren);
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|