Add support for context-aware cloning functions

Summary:
@public

Context-aware cloning functions are an internal Yoga feature that will be used for Yoga’s JNI code.

It will be possible to specify a context when calculating layout, which will be passed on to cloning functions. This will be a private feature.

Reviewed By: SidharthGuglani

Differential Revision: D14149470

fbshipit-source-id: 1d11106e65f9d872d10f191763da001f8d158a61
This commit is contained in:
David Aurelio
2019-02-20 11:52:38 -08:00
committed by Facebook Github Bot
parent b1c749075d
commit 2156de5fb5
6 changed files with 57 additions and 18 deletions

View File

@@ -32,7 +32,7 @@ TEST_F(ConfigCloningTest, uses_values_provided_by_cloning_callback) {
config->setCloneNodeCallback(cloneNode); config->setCloneNodeCallback(cloneNode);
YGNode node{}, owner{}; YGNode node{}, owner{};
auto clone = config->cloneNode(&node, &owner, 0); auto clone = config->cloneNode(&node, &owner, 0, nullptr);
ASSERT_EQ(clone, &clonedNode); ASSERT_EQ(clone, &clonedNode);
} }
@@ -43,12 +43,21 @@ TEST_F(
config->setCloneNodeCallback(doNotClone); config->setCloneNodeCallback(doNotClone);
YGNode node{}, owner{}; YGNode node{}, owner{};
auto clone = config->cloneNode(&node, &owner, 0); auto clone = config->cloneNode(&node, &owner, 0, nullptr);
ASSERT_NE(clone, nullptr); ASSERT_NE(clone, nullptr);
YGNodeFree(clone); YGNodeFree(clone);
} }
TEST_F(ConfigCloningTest, can_clone_with_context) {
config->setCloneNodeCallback([](YGNodeRef, YGNodeRef, int, void* context) {
return (YGNodeRef) context;
});
YGNode node{}, owner{}, clone{};
ASSERT_EQ(config->cloneNode(&node, &owner, 0, &clone), &clone);
}
void ConfigCloningTest::SetUp() { void ConfigCloningTest::SetUp() {
config = {YGConfigNew(), YGConfigFree}; config = {YGConfigNew(), YGConfigFree};
} }

View File

@@ -25,10 +25,16 @@ void YGConfig::log(
} }
} }
YGNodeRef YGConfig::cloneNode(YGNodeRef node, YGNodeRef owner, int childIndex) { YGNodeRef YGConfig::cloneNode(
YGNodeRef node,
YGNodeRef owner,
int childIndex,
void* cloneContext) {
YGNodeRef clone = nullptr; YGNodeRef clone = nullptr;
if (cloneNodeCallback_ != nullptr) { if (cloneNodeCallback_.noContext != nullptr) {
clone = cloneNodeCallback_(node, owner, childIndex); clone = cloneNodeUsesContext_
? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext)
: cloneNodeCallback_.noContext(node, owner, childIndex);
} }
if (clone == nullptr) { if (clone == nullptr) {
clone = YGNodeClone(node); clone = YGNodeClone(node);

View File

@@ -17,13 +17,22 @@ struct YGConfig {
void* context, void* context,
const char* format, const char* format,
va_list args); va_list args);
using CloneWithContextFn = YGNodeRef (*)(
YGNodeRef node,
YGNodeRef owner,
int childIndex,
void* cloneContext);
private: private:
YGCloneNodeFunc cloneNodeCallback_ = nullptr; union {
CloneWithContextFn withContext;
YGCloneNodeFunc noContext;
} cloneNodeCallback_;
union { union {
LogWithContextFn withContext; LogWithContextFn withContext;
YGLogger noContext; YGLogger noContext;
} logger_; } logger_;
bool cloneNodeUsesContext_;
bool loggerUsesContext_; bool loggerUsesContext_;
public: public:
@@ -51,8 +60,20 @@ public:
setLogger(YGLogger{nullptr}); setLogger(YGLogger{nullptr});
} }
YGNodeRef cloneNode(YGNodeRef node, YGNodeRef owner, int childIndex); YGNodeRef cloneNode(
YGNodeRef node,
YGNodeRef owner,
int childIndex,
void* cloneContext);
void setCloneNodeCallback(YGCloneNodeFunc cloneNode) { void setCloneNodeCallback(YGCloneNodeFunc cloneNode) {
cloneNodeCallback_ = cloneNode; cloneNodeCallback_.noContext = cloneNode;
cloneNodeUsesContext_ = false;
}
void setCloneNodeCallback(CloneWithContextFn cloneNode) {
cloneNodeCallback_.withContext = cloneNode;
cloneNodeUsesContext_ = true;
}
void setCloneNodeCallback(std::nullptr_t) {
setCloneNodeCallback(YGCloneNodeFunc{nullptr});
} }
}; };

View File

@@ -385,8 +385,8 @@ void YGNode::clearChildren() {
// Other Methods // Other Methods
void YGNode::cloneChildrenIfNeeded() { void YGNode::cloneChildrenIfNeeded(void* cloneContext) {
iterChildrenAfterCloningIfNeeded([](YGNodeRef) {}); iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext);
} }
void YGNode::markDirtyAndPropogate() { void YGNode::markDirtyAndPropogate() {

View File

@@ -146,16 +146,16 @@ public:
// Applies a callback to all children, after cloning them if they are not // Applies a callback to all children, after cloning them if they are not
// owned. // owned.
template <typename T> template <typename T>
void iterChildrenAfterCloningIfNeeded(T callback) { void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) {
int i = 0; int i = 0;
for (YGNodeRef& child : children_) { for (YGNodeRef& child : children_) {
if (child->getOwner() != this) { if (child->getOwner() != this) {
child = config_->cloneNode(child, this, i); child = config_->cloneNode(child, this, i, cloneContext);
child->setOwner(this); child->setOwner(this);
} }
i += 1; i += 1;
callback(child); callback(child, cloneContext);
} }
} }
@@ -335,7 +335,7 @@ public:
bool removeChild(YGNodeRef child); bool removeChild(YGNodeRef child);
void removeChild(uint32_t index); void removeChild(uint32_t index);
void cloneChildrenIfNeeded(); void cloneChildrenIfNeeded(void*);
void markDirtyAndPropogate(); void markDirtyAndPropogate();
float resolveFlexGrow(); float resolveFlexGrow();
float resolveFlexShrink(); float resolveFlexShrink();

View File

@@ -1789,13 +1789,16 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(
return false; return false;
} }
static void YGZeroOutLayoutRecursivly(const YGNodeRef node) { static void YGZeroOutLayoutRecursivly(
const YGNodeRef node,
void* layoutContext) {
node->getLayout() = {}; node->getLayout() = {};
node->setLayoutDimension(0, 0); node->setLayoutDimension(0, 0);
node->setLayoutDimension(0, 1); node->setLayoutDimension(0, 1);
node->setHasNewLayout(true); node->setHasNewLayout(true);
node->iterChildrenAfterCloningIfNeeded(YGZeroOutLayoutRecursivly); node->iterChildrenAfterCloningIfNeeded(
YGZeroOutLayoutRecursivly, layoutContext);
} }
static float YGNodeCalculateAvailableInnerDim( static float YGNodeCalculateAvailableInnerDim(
@@ -1877,7 +1880,7 @@ static float YGNodeComputeFlexBasisForChildren(
for (auto child : children) { for (auto child : children) {
child->resolveDimension(); child->resolveDimension();
if (child->getStyle().display == YGDisplayNone) { if (child->getStyle().display == YGDisplayNone) {
YGZeroOutLayoutRecursivly(child); YGZeroOutLayoutRecursivly(child, layoutContext);
child->setHasNewLayout(true); child->setHasNewLayout(true);
child->setDirty(false); child->setDirty(false);
continue; continue;
@@ -2751,7 +2754,7 @@ static void YGNodelayoutImpl(
// At this point we know we're going to perform work. Ensure that each child // At this point we know we're going to perform work. Ensure that each child
// has a mutable copy. // has a mutable copy.
node->cloneChildrenIfNeeded(); node->cloneChildrenIfNeeded(layoutContext);
// Reset layout flags, as they could have changed. // Reset layout flags, as they could have changed.
node->setLayoutHadOverflow(false); node->setLayoutHadOverflow(false);