Simplify Edge Resolution (#1550)
Summary: X-link: https://github.com/facebook/react-native/pull/42254 Pull Request resolved: https://github.com/facebook/yoga/pull/1550 This change aims to simplify how we resolve edges. This operation happens many, many times, and has gotten complex and slow when paired with StyleValuePool. This starts reshaping so that `yoga::Style` can resolve a style prop for a given edge. This is closer to the ideal computed style API to avoid recalcing this so many times, but doesn't address that. This relies on removing the errata related to row-reverse, and cleans up the removal started in the last change. This has no measurable perf effect under CompactValue, but has a >10% uplift in perf when using StyleValueHandle, where we can trivially check if a handle points to a defined value without resolving it, but only within `yoga::Style` since we don't expose the handle outside of it. More quantifiably, we go from 2.35 million StyleValuePool reads to 993k. The rest are checks on the handle. Reviewed By: joevilches Differential Revision: D52605596 fbshipit-source-id: 0b366963a899e376f99ce3d75cd5f14a25d60cec
This commit is contained in:
committed by
Facebook GitHub Bot
parent
35b9b5223e
commit
8744792f41
@@ -9,7 +9,6 @@
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
|
||||
#include <yoga/algorithm/FlexDirection.h>
|
||||
#include <yoga/debug/AssertFatal.h>
|
||||
#include <yoga/node/Node.h>
|
||||
#include <yoga/numeric/Comparison.h>
|
||||
@@ -49,326 +48,6 @@ Node::Node(Node&& node) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Edge value resolution should be moved to `yoga::Style`
|
||||
template <auto Field>
|
||||
Style::Length Node::computeEdgeValueForRow(Edge rowEdge, Edge edge) const {
|
||||
if ((style_.*Field)(rowEdge).isDefined()) {
|
||||
return (style_.*Field)(rowEdge);
|
||||
} else if ((style_.*Field)(edge).isDefined()) {
|
||||
return (style_.*Field)(edge);
|
||||
} else if ((style_.*Field)(Edge::Horizontal).isDefined()) {
|
||||
return (style_.*Field)(Edge::Horizontal);
|
||||
} else {
|
||||
return (style_.*Field)(Edge::All);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Edge value resolution should be moved to `yoga::Style`
|
||||
template <auto Field>
|
||||
Style::Length Node::computeEdgeValueForColumn(Edge edge) const {
|
||||
if ((style_.*Field)(edge).isDefined()) {
|
||||
return (style_.*Field)(edge);
|
||||
} else if ((style_.*Field)(Edge::Vertical).isDefined()) {
|
||||
return (style_.*Field)(Edge::Vertical);
|
||||
} else {
|
||||
return (style_.*Field)(Edge::All);
|
||||
}
|
||||
}
|
||||
|
||||
Edge Node::getInlineStartEdge(FlexDirection flexDirection, Direction direction)
|
||||
const {
|
||||
return inlineStartEdge(flexDirection, direction);
|
||||
}
|
||||
|
||||
Edge Node::getInlineEndEdge(FlexDirection flexDirection, Direction direction)
|
||||
const {
|
||||
return inlineEndEdge(flexDirection, direction);
|
||||
}
|
||||
|
||||
Edge Node::getFlexStartRelativeEdge(
|
||||
FlexDirection flexDirection,
|
||||
Direction direction) const {
|
||||
return flexStartRelativeEdge(flexDirection, direction);
|
||||
}
|
||||
|
||||
Edge Node::getFlexEndRelativeEdge(
|
||||
FlexDirection flexDirection,
|
||||
Direction direction) const {
|
||||
return flexEndRelativeEdge(flexDirection, direction);
|
||||
}
|
||||
|
||||
bool Node::isFlexStartPositionDefined(FlexDirection axis, Direction direction)
|
||||
const {
|
||||
auto leadingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(
|
||||
getFlexStartRelativeEdge(axis, direction), flexStartEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::position>(flexStartEdge(axis));
|
||||
|
||||
return leadingPosition.isDefined();
|
||||
}
|
||||
|
||||
bool Node::isInlineStartPositionDefined(FlexDirection axis, Direction direction)
|
||||
const {
|
||||
Edge startEdge = getInlineStartEdge(axis, direction);
|
||||
Style::Length leadingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge)
|
||||
: computeEdgeValueForColumn<&Style::position>(startEdge);
|
||||
|
||||
return leadingPosition.isDefined();
|
||||
}
|
||||
|
||||
bool Node::isFlexEndPositionDefined(FlexDirection axis, Direction direction)
|
||||
const {
|
||||
auto trailingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(
|
||||
getFlexEndRelativeEdge(axis, direction), flexEndEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::position>(flexEndEdge(axis));
|
||||
|
||||
return !trailingPosition.isUndefined();
|
||||
}
|
||||
|
||||
bool Node::isInlineEndPositionDefined(FlexDirection axis, Direction direction)
|
||||
const {
|
||||
Edge endEdge = getInlineEndEdge(axis, direction);
|
||||
Style::Length trailingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge)
|
||||
: computeEdgeValueForColumn<&Style::position>(endEdge);
|
||||
|
||||
return trailingPosition.isDefined();
|
||||
}
|
||||
|
||||
float Node::getFlexStartPosition(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float axisSize) const {
|
||||
auto leadingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(
|
||||
getFlexStartRelativeEdge(axis, direction), flexStartEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::position>(flexStartEdge(axis));
|
||||
|
||||
return leadingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineStartPosition(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float axisSize) const {
|
||||
Edge startEdge = getInlineStartEdge(axis, direction);
|
||||
Style::Length leadingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge)
|
||||
: computeEdgeValueForColumn<&Style::position>(startEdge);
|
||||
|
||||
return leadingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexEndPosition(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float axisSize) const {
|
||||
auto trailingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(
|
||||
getFlexEndRelativeEdge(axis, direction), flexEndEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::position>(flexEndEdge(axis));
|
||||
|
||||
return trailingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineEndPosition(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float axisSize) const {
|
||||
Edge endEdge = getInlineEndEdge(axis, direction);
|
||||
Style::Length trailingPosition = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge)
|
||||
: computeEdgeValueForColumn<&Style::position>(endEdge);
|
||||
|
||||
return trailingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexStartMargin(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
auto leadingMargin = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::margin>(
|
||||
getFlexStartRelativeEdge(axis, direction), flexStartEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::margin>(flexStartEdge(axis));
|
||||
|
||||
return leadingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineStartMargin(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
Edge startEdge = getInlineStartEdge(axis, direction);
|
||||
Style::Length leadingMargin = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::margin>(Edge::Start, startEdge)
|
||||
: computeEdgeValueForColumn<&Style::margin>(startEdge);
|
||||
|
||||
return leadingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexEndMargin(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
auto trailingMargin = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::margin>(
|
||||
getFlexEndRelativeEdge(axis, direction), flexEndEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::margin>(flexEndEdge(axis));
|
||||
|
||||
return trailingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineEndMargin(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
Edge endEdge = getInlineEndEdge(axis, direction);
|
||||
Style::Length trailingMargin = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::margin>(Edge::End, endEdge)
|
||||
: computeEdgeValueForColumn<&Style::margin>(endEdge);
|
||||
|
||||
return trailingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineStartBorder(FlexDirection axis, Direction direction)
|
||||
const {
|
||||
Edge startEdge = getInlineStartEdge(axis, direction);
|
||||
Style::Length leadingBorder = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::border>(Edge::Start, startEdge)
|
||||
: computeEdgeValueForColumn<&Style::border>(startEdge);
|
||||
|
||||
return maxOrDefined(leadingBorder.value().unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexStartBorder(FlexDirection axis, Direction direction) const {
|
||||
Style::Length leadingBorder = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::border>(
|
||||
getFlexStartRelativeEdge(axis, direction), flexStartEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::border>(flexStartEdge(axis));
|
||||
|
||||
return maxOrDefined(leadingBorder.value().unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineEndBorder(FlexDirection axis, Direction direction) const {
|
||||
Edge endEdge = getInlineEndEdge(axis, direction);
|
||||
Style::Length trailingBorder = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::border>(Edge::End, endEdge)
|
||||
: computeEdgeValueForColumn<&Style::border>(endEdge);
|
||||
|
||||
return maxOrDefined(trailingBorder.value().unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexEndBorder(FlexDirection axis, Direction direction) const {
|
||||
Style::Length trailingBorder = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::border>(
|
||||
getFlexEndRelativeEdge(axis, direction), flexEndEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::border>(flexEndEdge(axis));
|
||||
|
||||
return maxOrDefined(trailingBorder.value().unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineStartPadding(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
Edge startEdge = getInlineStartEdge(axis, direction);
|
||||
Style::Length leadingPadding = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::padding>(Edge::Start, startEdge)
|
||||
: computeEdgeValueForColumn<&Style::padding>(startEdge);
|
||||
|
||||
return maxOrDefined(leadingPadding.resolve(widthSize).unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexStartPadding(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
auto leadingPadding = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::padding>(
|
||||
getFlexStartRelativeEdge(axis, direction), flexStartEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::padding>(flexStartEdge(axis));
|
||||
|
||||
return maxOrDefined(leadingPadding.resolve(widthSize).unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineEndPadding(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
Edge endEdge = getInlineEndEdge(axis, direction);
|
||||
Style::Length trailingPadding = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::padding>(Edge::End, endEdge)
|
||||
: computeEdgeValueForColumn<&Style::padding>(endEdge);
|
||||
|
||||
return maxOrDefined(trailingPadding.resolve(widthSize).unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getFlexEndPadding(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
auto trailingPadding = isRow(axis)
|
||||
? computeEdgeValueForRow<&Style::padding>(
|
||||
getFlexEndRelativeEdge(axis, direction), flexEndEdge(axis))
|
||||
: computeEdgeValueForColumn<&Style::padding>(flexEndEdge(axis));
|
||||
|
||||
return maxOrDefined(trailingPadding.resolve(widthSize).unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
float Node::getInlineStartPaddingAndBorder(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
return getInlineStartPadding(axis, direction, widthSize) +
|
||||
getInlineStartBorder(axis, direction);
|
||||
}
|
||||
|
||||
float Node::getFlexStartPaddingAndBorder(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
return getFlexStartPadding(axis, direction, widthSize) +
|
||||
getFlexStartBorder(axis, direction);
|
||||
}
|
||||
|
||||
float Node::getInlineEndPaddingAndBorder(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
return getInlineEndPadding(axis, direction, widthSize) +
|
||||
getInlineEndBorder(axis, direction);
|
||||
}
|
||||
|
||||
float Node::getFlexEndPaddingAndBorder(
|
||||
FlexDirection axis,
|
||||
Direction direction,
|
||||
float widthSize) const {
|
||||
return getFlexEndPadding(axis, direction, widthSize) +
|
||||
getFlexEndBorder(axis, direction);
|
||||
}
|
||||
|
||||
float Node::getBorderForAxis(FlexDirection axis) const {
|
||||
return getInlineStartBorder(axis, Direction::LTR) +
|
||||
getInlineEndBorder(axis, Direction::LTR);
|
||||
}
|
||||
|
||||
float Node::getMarginForAxis(FlexDirection axis, float widthSize) const {
|
||||
// The total margin for a given axis does not depend on the direction
|
||||
// so hardcoding LTR here to avoid piping direction to this function
|
||||
return getInlineStartMargin(axis, Direction::LTR, widthSize) +
|
||||
getInlineEndMargin(axis, Direction::LTR, widthSize);
|
||||
}
|
||||
|
||||
float Node::getGapForAxis(FlexDirection axis) const {
|
||||
auto gap = isRow(axis) ? style_.resolveColumnGap() : style_.resolveRowGap();
|
||||
// TODO: Validate percentage gap, and expose ability to set percentage to
|
||||
// public API
|
||||
return maxOrDefined(gap.resolve(0.0f /*ownerSize*/).unwrap(), 0.0f);
|
||||
}
|
||||
|
||||
YGSize Node::measure(
|
||||
float width,
|
||||
MeasureMode widthMode,
|
||||
@@ -386,7 +65,7 @@ float Node::dimensionWithMargin(
|
||||
const FlexDirection axis,
|
||||
const float widthSize) {
|
||||
return getLayout().measuredDimension(dimension(axis)) +
|
||||
getMarginForAxis(axis, widthSize);
|
||||
style_.computeMarginForAxis(axis, widthSize);
|
||||
}
|
||||
|
||||
bool Node::isLayoutDimensionDefined(const FlexDirection axis) {
|
||||
@@ -470,15 +149,15 @@ void Node::setLayoutDirection(Direction direction) {
|
||||
layout_.setDirection(direction);
|
||||
}
|
||||
|
||||
void Node::setLayoutMargin(float margin, Edge edge) {
|
||||
void Node::setLayoutMargin(float margin, PhysicalEdge edge) {
|
||||
layout_.setMargin(edge, margin);
|
||||
}
|
||||
|
||||
void Node::setLayoutBorder(float border, Edge edge) {
|
||||
void Node::setLayoutBorder(float border, PhysicalEdge edge) {
|
||||
layout_.setBorder(edge, border);
|
||||
}
|
||||
|
||||
void Node::setLayoutPadding(float padding, Edge edge) {
|
||||
void Node::setLayoutPadding(float padding, PhysicalEdge edge) {
|
||||
layout_.setPadding(edge, padding);
|
||||
}
|
||||
|
||||
@@ -490,7 +169,7 @@ void Node::setLayoutComputedFlexBasis(const FloatOptional computedFlexBasis) {
|
||||
layout_.computedFlexBasis = computedFlexBasis;
|
||||
}
|
||||
|
||||
void Node::setLayoutPosition(float position, Edge edge) {
|
||||
void Node::setLayoutPosition(float position, PhysicalEdge edge) {
|
||||
layout_.setPosition(edge, position);
|
||||
}
|
||||
|
||||
@@ -523,11 +202,11 @@ float Node::relativePosition(
|
||||
if (style_.positionType() == PositionType::Static) {
|
||||
return 0;
|
||||
}
|
||||
if (isInlineStartPositionDefined(axis, direction)) {
|
||||
return getInlineStartPosition(axis, direction, axisSize);
|
||||
if (style_.isInlineStartPositionDefined(axis, direction)) {
|
||||
return style_.computeInlineStartPosition(axis, direction, axisSize);
|
||||
}
|
||||
|
||||
return -1 * getInlineEndPosition(axis, direction, axisSize);
|
||||
return -1 * style_.computeInlineEndPosition(axis, direction, axisSize);
|
||||
}
|
||||
|
||||
void Node::setPosition(
|
||||
@@ -551,45 +230,29 @@ void Node::setPosition(
|
||||
const float relativePositionCross =
|
||||
relativePosition(crossAxis, directionRespectingRoot, crossSize);
|
||||
|
||||
const Edge mainAxisLeadingEdge = getInlineStartEdge(mainAxis, direction);
|
||||
const Edge mainAxisTrailingEdge = getInlineEndEdge(mainAxis, direction);
|
||||
const Edge crossAxisLeadingEdge = getInlineStartEdge(crossAxis, direction);
|
||||
const Edge crossAxisTrailingEdge = getInlineEndEdge(crossAxis, direction);
|
||||
const auto mainAxisLeadingEdge = inlineStartEdge(mainAxis, direction);
|
||||
const auto mainAxisTrailingEdge = inlineEndEdge(mainAxis, direction);
|
||||
const auto crossAxisLeadingEdge = inlineStartEdge(crossAxis, direction);
|
||||
const auto crossAxisTrailingEdge = inlineEndEdge(crossAxis, direction);
|
||||
|
||||
setLayoutPosition(
|
||||
(getInlineStartMargin(mainAxis, direction, ownerWidth) +
|
||||
(style_.computeInlineStartMargin(mainAxis, direction, ownerWidth) +
|
||||
relativePositionMain),
|
||||
mainAxisLeadingEdge);
|
||||
setLayoutPosition(
|
||||
(getInlineEndMargin(mainAxis, direction, ownerWidth) +
|
||||
(style_.computeInlineEndMargin(mainAxis, direction, ownerWidth) +
|
||||
relativePositionMain),
|
||||
mainAxisTrailingEdge);
|
||||
setLayoutPosition(
|
||||
(getInlineStartMargin(crossAxis, direction, ownerWidth) +
|
||||
(style_.computeInlineStartMargin(crossAxis, direction, ownerWidth) +
|
||||
relativePositionCross),
|
||||
crossAxisLeadingEdge);
|
||||
setLayoutPosition(
|
||||
(getInlineEndMargin(crossAxis, direction, ownerWidth) +
|
||||
(style_.computeInlineEndMargin(crossAxis, direction, ownerWidth) +
|
||||
relativePositionCross),
|
||||
crossAxisTrailingEdge);
|
||||
}
|
||||
|
||||
Style::Length Node::getFlexStartMarginValue(FlexDirection axis) const {
|
||||
if (isRow(axis) && style_.margin(Edge::Start).isDefined()) {
|
||||
return style_.margin(Edge::Start);
|
||||
} else {
|
||||
return style_.margin(flexStartEdge(axis));
|
||||
}
|
||||
}
|
||||
|
||||
Style::Length Node::marginTrailingValue(FlexDirection axis) const {
|
||||
if (isRow(axis) && style_.margin(Edge::End).isDefined()) {
|
||||
return style_.margin(Edge::End);
|
||||
} else {
|
||||
return style_.margin(flexEndEdge(axis));
|
||||
}
|
||||
}
|
||||
|
||||
Style::Length Node::resolveFlexBasisPtr() const {
|
||||
Style::Length flexBasis = style_.flexBasis();
|
||||
if (flexBasis.unit() != Unit::Auto && flexBasis.unit() != Unit::Undefined) {
|
||||
|
Reference in New Issue
Block a user