Skip to content

Commit

Permalink
Remove the use of legacy flag and log the diff if its used
Browse files Browse the repository at this point in the history
Reviewed By: emilsjolander

Differential Revision: D6856812

fbshipit-source-id: e4724d80702cc75c1894e348e137b24e663573d2
  • Loading branch information
priteshrnandgaonkar authored and facebook-github-bot committed Feb 2, 2018
1 parent 752427b commit 9f7cedb
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 7 deletions.
61 changes: 61 additions & 0 deletions ReactCommon/yoga/yoga/YGNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,13 @@ void YGNode::markDirtyAndPropogate() {
}
}

void YGNode::markDirtyAndPropogateDownwards() {
isDirty_ = true;
for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
childNode->markDirtyAndPropogateDownwards();
});
}

float YGNode::resolveFlexGrow() {
// Root nodes flexGrow should always be 0
if (parent_ == nullptr) {
Expand Down Expand Up @@ -666,3 +673,57 @@ float YGNode::getLeadingPaddingAndBorder(
const float widthSize) {
return getLeadingPadding(axis, widthSize) + getLeadingBorder(axis);
}

bool YGNode::didUseLegacyFlag() {
bool didUseLegacyFlag = layout_.didUseLegacyFlag;
if (didUseLegacyFlag) {
return true;
}
for (const auto& child : children_) {
if (child->layout_.didUseLegacyFlag) {
didUseLegacyFlag = true;
break;
}
}
return didUseLegacyFlag;
}

void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
config_->useLegacyStretchBehaviour = useLegacyFlag;
for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
});
}

void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
bool doesLegacyFlagAffectsLayout) {
layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
}

void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
layout_.didUseLegacyFlag = didUseLegacyFlag;
}

bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
if (children_.size() != node.children_.size()) {
return false;
}
if (layout_ != node.layout_) {
return false;
}
if (children_.size() == 0) {
return true;
}

bool isLayoutTreeEqual = true;
YGNodeRef otherNodeChildren = nullptr;
for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
otherNodeChildren = node.children_[i];
isLayoutTreeEqual =
children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
if (!isLayoutTreeEqual) {
return false;
}
}
return isLayoutTreeEqual;
}
6 changes: 6 additions & 0 deletions ReactCommon/yoga/yoga/YGNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ struct YGNode {
const float mainSize,
const float crossSize,
const float parentWidth);
void setAndPropogateUseLegacyFlag(bool useLegacyFlag);
void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout);
void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag);
void markDirtyAndPropogateDownwards();

// Other methods
YGValue marginLeadingValue(const YGFlexDirection axis) const;
Expand All @@ -150,4 +154,6 @@ struct YGNode {
float resolveFlexGrow();
float resolveFlexShrink();
bool isNodeFlexible();
bool didUseLegacyFlag();
bool isLayoutTreeEqualToNode(const YGNode& node) const;
};
76 changes: 72 additions & 4 deletions ReactCommon/yoga/yoga/Yoga-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,43 @@ bool YGValueArrayEqual(
return areEqual;
}

typedef struct YGCachedMeasurement {
struct YGCachedMeasurement {
float availableWidth;
float availableHeight;
YGMeasureMode widthMeasureMode;
YGMeasureMode heightMeasureMode;

float computedWidth;
float computedHeight;
} YGCachedMeasurement;

bool operator==(YGCachedMeasurement measurement) const {
bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
heightMeasureMode == measurement.heightMeasureMode;

if (!std::isnan(availableWidth) ||
!std::isnan(measurement.availableWidth)) {
isEqual = isEqual && availableWidth == measurement.availableWidth;
}
if (!std::isnan(availableHeight) ||
!std::isnan(measurement.availableHeight)) {
isEqual = isEqual && availableHeight == measurement.availableHeight;
}
if (!std::isnan(computedWidth) || !std::isnan(measurement.computedWidth)) {
isEqual = isEqual && computedWidth == measurement.computedWidth;
}
if (!std::isnan(
computedHeight || !std::isnan(measurement.computedHeight))) {
isEqual = isEqual && computedHeight == measurement.computedHeight;
}

return availableWidth == measurement.availableWidth &&
availableHeight == measurement.availableHeight &&
widthMeasureMode == measurement.widthMeasureMode &&
heightMeasureMode == measurement.heightMeasureMode &&
computedWidth == measurement.computedWidth &&
computedHeight == measurement.computedHeight;
}
};

// This value was chosen based on empiracle data. Even the most complicated
// layouts should not require more than 16 entries to fit within the cache.
Expand Down Expand Up @@ -80,6 +108,44 @@ struct YGLayout {
std::array<float, 2> measuredDimensions;

YGCachedMeasurement cachedLayout;
bool didUseLegacyFlag;
bool doesLegacyStretchFlagAffectsLayout;

bool operator==(YGLayout layout) const {
bool isEqual = position == layout.position &&
dimensions == layout.dimensions && margin == layout.margin &&
border == layout.border && padding == layout.padding &&
direction == layout.direction && hadOverflow == layout.hadOverflow &&
lastParentDirection == layout.lastParentDirection &&
nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
cachedLayout == layout.cachedLayout;

for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) {
isEqual =
isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i];
}

if (!YGFloatIsUndefined(computedFlexBasis) ||
!YGFloatIsUndefined(layout.computedFlexBasis)) {
isEqual = isEqual && (computedFlexBasis == layout.computedFlexBasis);
}
if (!YGFloatIsUndefined(measuredDimensions[0]) ||
!YGFloatIsUndefined(layout.measuredDimensions[0])) {
isEqual =
isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]);
}
if (!YGFloatIsUndefined(measuredDimensions[1]) ||
!YGFloatIsUndefined(layout.measuredDimensions[1])) {
isEqual =
isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]);
}

return isEqual;
}

bool operator!=(YGLayout layout) const {
return !(*this == layout);
}
};

struct YGStyle {
Expand Down Expand Up @@ -150,15 +216,15 @@ struct YGStyle {
}
};

typedef struct YGConfig {
struct YGConfig {
bool experimentalFeatures[YGExperimentalFeatureCount + 1];
bool useWebDefaults;
bool useLegacyStretchBehaviour;
float pointScaleFactor;
YGLogger logger;
YGNodeClonedFunc cloneNodeCallback;
void* context;
} YGConfig;
};

#define YG_UNDEFINED_VALUES \
{ .value = YGUndefined, .unit = YGUnitUndefined }
Expand Down Expand Up @@ -272,6 +338,8 @@ static const YGLayout gYGNodeLayoutDefaults = {
.computedWidth = -1,
.computedHeight = -1,
},
.didUseLegacyFlag = false,
.doesLegacyStretchFlagAffectsLayout = false,
};

extern bool YGFloatsEqual(const float a, const float b);
Expand Down
90 changes: 87 additions & 3 deletions ReactCommon/yoga/yoga/Yoga.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ bool YGNodeIsDirty(YGNodeRef node) {
return node->isDirty();
}

bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) {
return node->didUseLegacyFlag();
}

int32_t gNodeInstanceCount = 0;
int32_t gConfigInstanceCount = 0;

Expand Down Expand Up @@ -243,6 +247,29 @@ YGNodeRef YGNodeClone(YGNodeRef oldNode) {
return node;
}

static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
YGNodeRef node = YGNodeClone(oldNode);
YGVector vec = YGVector();
vec.reserve(oldNode->getChildren().size());
YGNodeRef childNode = nullptr;
for (auto& item : oldNode->getChildren()) {
childNode = YGNodeDeepClone(item);
childNode->setParent(node);
vec.push_back(childNode);
}
node->setChildren(vec);

if (oldNode->getNextChild() != nullptr) {
node->setNextChild(YGNodeDeepClone(oldNode->getNextChild()));
}

if (node->getConfig() != nullptr) {
node->setConfig(new YGConfig(*node->getConfig()));
}

return node;
}

void YGNodeFree(const YGNodeRef node) {
if (node->getParent()) {
node->getParent()->removeChild(node);
Expand Down Expand Up @@ -1975,10 +2002,15 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} else {
if (!node->getConfig()->useLegacyStretchBehaviour &&
(totalFlexGrowFactors == 0 || node->resolveFlexGrow() == 0)) {
// If we don't have any children to flex or we can't flex the node itself,
// space we've used is all space we need. Root node also should be shrunk to minimum
// If we don't have any children to flex or we can't flex the node
// itself, space we've used is all space we need. Root node also
// should be shrunk to minimum
availableInnerMainDim = sizeConsumedOnCurrentLine;
}

if (node->getConfig()->useLegacyStretchBehaviour) {
node->setLayoutDidUseLegacyFlag(true);
}
sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour;
}
}
Expand Down Expand Up @@ -3330,7 +3362,6 @@ void YGNodeCalculateLayout(const YGNodeRef node,
// input
// parameters don't change.
gCurrentGenerationCount++;

node->resolveDimension();
float width = YGUndefined;
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
Expand Down Expand Up @@ -3396,6 +3427,59 @@ void YGNodeCalculateLayout(const YGNodeRef node,
YGPrintOptionsStyle));
}
}

bool didUseLegacyFlag = node->didUseLegacyFlag();

// We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we
// aren't sure whether client's of yoga have gotten rid off this flag or not.
// So logging this in YGLayout would help to find out the call sites depending
// on this flag. This check would be removed once we are sure no one is
// dependent on this flag anymore.
if (didUseLegacyFlag) {
const YGNodeRef originalNode = YGNodeDeepClone(node);
originalNode->resolveDimension();
// Recursively mark nodes as dirty
originalNode->markDirtyAndPropogateDownwards();
gCurrentGenerationCount++;
// Rerun the layout, and calculate the diff
originalNode->setAndPropogateUseLegacyFlag(false);
if (YGLayoutNodeInternal(
originalNode,
width,
height,
parentDirection,
widthMeasureMode,
heightMeasureMode,
parentWidth,
parentHeight,
true,
"initial",
originalNode->getConfig())) {
originalNode->setPosition(
originalNode->getLayout().direction,
parentWidth,
parentHeight,
parentWidth);
YGRoundToPixelGrid(
originalNode,
originalNode->getConfig()->pointScaleFactor,
0.0f,
0.0f);

// Set whether the two layouts are different or not.
node->setLayoutDoesLegacyFlagAffectsLayout(
!originalNode->isLayoutTreeEqualToNode(*node));

if (gPrintTree) {
YGNodePrint(
originalNode,
(YGPrintOptions)(
YGPrintOptionsLayout | YGPrintOptionsChildren |
YGPrintOptionsStyle));
}
}
YGNodeFreeRecursive(originalNode);
}
}

void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
Expand Down
1 change: 1 addition & 0 deletions ReactCommon/yoga/yoga/Yoga.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
YGNodeType YGNodeGetNodeType(YGNodeRef node);
void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
bool YGNodeIsDirty(YGNodeRef node);
bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node);

YG_NODE_STYLE_PROPERTY(YGDirection, Direction, direction);
YG_NODE_STYLE_PROPERTY(YGFlexDirection, FlexDirection, flexDirection);
Expand Down

0 comments on commit 9f7cedb

Please sign in to comment.