Remove the use of legacy flag and log the diff if its used

Reviewed By: emilsjolander

Differential Revision: D6856812

fbshipit-source-id: e4724d80702cc75c1894e348e137b24e663573d2
This commit is contained in:
Pritesh Nandgaonkar 2018-02-02 07:38:17 -08:00 committed by Facebook Github Bot
parent 752427b7b8
commit 9f7cedbe14
5 changed files with 227 additions and 7 deletions

View File

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

View File

@ -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;
@ -150,4 +154,6 @@ struct YGNode {
float resolveFlexGrow();
float resolveFlexShrink();
bool isNodeFlexible();
bool didUseLegacyFlag();
bool isLayoutTreeEqualToNode(const YGNode& node) const;
};

View File

@ -44,7 +44,7 @@ bool YGValueArrayEqual(
return areEqual;
}
typedef struct YGCachedMeasurement {
struct YGCachedMeasurement {
float availableWidth;
float availableHeight;
YGMeasureMode widthMeasureMode;
@ -52,7 +52,35 @@ typedef struct YGCachedMeasurement {
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.
@ -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 {
@ -150,7 +216,7 @@ struct YGStyle {
}
};
typedef struct YGConfig {
struct YGConfig {
bool experimentalFeatures[YGExperimentalFeatureCount + 1];
bool useWebDefaults;
bool useLegacyStretchBehaviour;
@ -158,7 +224,7 @@ typedef struct YGConfig {
YGLogger logger;
YGNodeClonedFunc cloneNodeCallback;
void* context;
} YGConfig;
};
#define YG_UNDEFINED_VALUES \
{ .value = YGUndefined, .unit = YGUnitUndefined }
@ -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);

View File

@ -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;
@ -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);
@ -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;
}
}
@ -3330,7 +3362,6 @@ void YGNodeCalculateLayout(const YGNodeRef node,
// input
// parameters don't change.
gCurrentGenerationCount++;
node->resolveDimension();
float width = YGUndefined;
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
@ -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) {

View File

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