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);
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};
}

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;
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);

View File

@@ -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});
}
};

View File

@@ -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() {

View File

@@ -146,16 +146,16 @@ public:
// Applies a callback to all children, after cloning them if they are not
// owned.
template <typename T>
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();

View File

@@ -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);