From 2156de5fb5c4892708cc0b475b464cf7734d4be7 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Wed, 20 Feb 2019 11:52:38 -0800 Subject: [PATCH] Add support for context-aware cloning functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- tests/YGConfigTest.cpp | 13 +++++++++++-- yoga/YGConfig.cpp | 12 +++++++++--- yoga/YGConfig.h | 27 ++++++++++++++++++++++++--- yoga/YGNode.cpp | 4 ++-- yoga/YGNode.h | 8 ++++---- yoga/Yoga.cpp | 11 +++++++---- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/tests/YGConfigTest.cpp b/tests/YGConfigTest.cpp index c8271448..9aa33e00 100644 --- a/tests/YGConfigTest.cpp +++ b/tests/YGConfigTest.cpp @@ -32,7 +32,7 @@ TEST_F(ConfigCloningTest, uses_values_provided_by_cloning_callback) { config->setCloneNodeCallback(cloneNode); YGNode node{}, owner{}; - auto clone = config->cloneNode(&node, &owner, 0); + auto clone = config->cloneNode(&node, &owner, 0, nullptr); ASSERT_EQ(clone, &clonedNode); } @@ -43,12 +43,21 @@ TEST_F( config->setCloneNodeCallback(doNotClone); YGNode node{}, owner{}; - auto clone = config->cloneNode(&node, &owner, 0); + auto clone = config->cloneNode(&node, &owner, 0, nullptr); ASSERT_NE(clone, nullptr); 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() { config = {YGConfigNew(), YGConfigFree}; } diff --git a/yoga/YGConfig.cpp b/yoga/YGConfig.cpp index 6527e587..773ad24a 100644 --- a/yoga/YGConfig.cpp +++ b/yoga/YGConfig.cpp @@ -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; - if (cloneNodeCallback_ != nullptr) { - clone = cloneNodeCallback_(node, owner, childIndex); + if (cloneNodeCallback_.noContext != nullptr) { + clone = cloneNodeUsesContext_ + ? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext) + : cloneNodeCallback_.noContext(node, owner, childIndex); } if (clone == nullptr) { clone = YGNodeClone(node); diff --git a/yoga/YGConfig.h b/yoga/YGConfig.h index 11fe678b..ec87c7a4 100644 --- a/yoga/YGConfig.h +++ b/yoga/YGConfig.h @@ -17,13 +17,22 @@ struct YGConfig { void* context, const char* format, va_list args); + using CloneWithContextFn = YGNodeRef (*)( + YGNodeRef node, + YGNodeRef owner, + int childIndex, + void* cloneContext); private: - YGCloneNodeFunc cloneNodeCallback_ = nullptr; + union { + CloneWithContextFn withContext; + YGCloneNodeFunc noContext; + } cloneNodeCallback_; union { LogWithContextFn withContext; YGLogger noContext; } logger_; + bool cloneNodeUsesContext_; bool loggerUsesContext_; public: @@ -51,8 +60,20 @@ public: 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) { - cloneNodeCallback_ = cloneNode; + cloneNodeCallback_.noContext = cloneNode; + cloneNodeUsesContext_ = false; + } + void setCloneNodeCallback(CloneWithContextFn cloneNode) { + cloneNodeCallback_.withContext = cloneNode; + cloneNodeUsesContext_ = true; + } + void setCloneNodeCallback(std::nullptr_t) { + setCloneNodeCallback(YGCloneNodeFunc{nullptr}); } }; diff --git a/yoga/YGNode.cpp b/yoga/YGNode.cpp index fedb3b9e..d1601272 100644 --- a/yoga/YGNode.cpp +++ b/yoga/YGNode.cpp @@ -385,8 +385,8 @@ void YGNode::clearChildren() { // Other Methods -void YGNode::cloneChildrenIfNeeded() { - iterChildrenAfterCloningIfNeeded([](YGNodeRef) {}); +void YGNode::cloneChildrenIfNeeded(void* cloneContext) { + iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext); } void YGNode::markDirtyAndPropogate() { diff --git a/yoga/YGNode.h b/yoga/YGNode.h index 3c2a9903..0eee85e7 100644 --- a/yoga/YGNode.h +++ b/yoga/YGNode.h @@ -146,16 +146,16 @@ public: // Applies a callback to all children, after cloning them if they are not // owned. template - void iterChildrenAfterCloningIfNeeded(T callback) { + void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) { int i = 0; for (YGNodeRef& child : children_) { if (child->getOwner() != this) { - child = config_->cloneNode(child, this, i); + child = config_->cloneNode(child, this, i, cloneContext); child->setOwner(this); } i += 1; - callback(child); + callback(child, cloneContext); } } @@ -335,7 +335,7 @@ public: bool removeChild(YGNodeRef child); void removeChild(uint32_t index); - void cloneChildrenIfNeeded(); + void cloneChildrenIfNeeded(void*); void markDirtyAndPropogate(); float resolveFlexGrow(); float resolveFlexShrink(); diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index 22c2a038..ebba2476 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -1789,13 +1789,16 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( return false; } -static void YGZeroOutLayoutRecursivly(const YGNodeRef node) { +static void YGZeroOutLayoutRecursivly( + const YGNodeRef node, + void* layoutContext) { node->getLayout() = {}; node->setLayoutDimension(0, 0); node->setLayoutDimension(0, 1); node->setHasNewLayout(true); - node->iterChildrenAfterCloningIfNeeded(YGZeroOutLayoutRecursivly); + node->iterChildrenAfterCloningIfNeeded( + YGZeroOutLayoutRecursivly, layoutContext); } static float YGNodeCalculateAvailableInnerDim( @@ -1877,7 +1880,7 @@ static float YGNodeComputeFlexBasisForChildren( for (auto child : children) { child->resolveDimension(); if (child->getStyle().display == YGDisplayNone) { - YGZeroOutLayoutRecursivly(child); + YGZeroOutLayoutRecursivly(child, layoutContext); child->setHasNewLayout(true); child->setDirty(false); continue; @@ -2751,7 +2754,7 @@ static void YGNodelayoutImpl( // At this point we know we're going to perform work. Ensure that each child // has a mutable copy. - node->cloneChildrenIfNeeded(); + node->cloneChildrenIfNeeded(layoutContext); // Reset layout flags, as they could have changed. node->setLayoutHadOverflow(false);