Skip to content

Commit

Permalink
Fix measure when view is inverted
Browse files Browse the repository at this point in the history
Summary:
changelog: [internal]

Vertical and horizontal inversion was not taken into account in `computeRelativeLayoutMetrics`. To fix it, we precompute frames to include inversions.

Reviewed By: mdvacca

Differential Revision: D37994809

fbshipit-source-id: 043e6f19b6fa577f61fa3c739ce2d751ef973cc3
  • Loading branch information
sammy-SC authored and facebook-github-bot committed Jul 21, 2022
1 parent 143a0f7 commit 64528e5
Show file tree
Hide file tree
Showing 5 changed files with 451 additions and 8 deletions.
73 changes: 67 additions & 6 deletions ReactCommon/react/renderer/core/LayoutableShadowNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,60 @@
namespace facebook {
namespace react {

template <class T>
using LayoutableSmallVector = butter::small_vector<T, 16>;

static LayoutableSmallVector<Rect> calculateTransformedFrames(
LayoutableSmallVector<ShadowNode const *> const &shadowNodeList,
LayoutableShadowNode::LayoutInspectingPolicy policy) {
auto size = shadowNodeList.size();
auto transformedFrames = LayoutableSmallVector<Rect>{size};
auto transformation = Transform::Identity();

for (int i = size - 1; i >= 0; --i) {
auto currentShadowNode =
traitCast<LayoutableShadowNode const *>(shadowNodeList.at(i));
auto currentFrame = currentShadowNode->getLayoutMetrics().frame;

if (policy.includeTransform) {
if (Transform::isVerticalInversion(transformation)) {
auto parentShadowNode =
traitCast<LayoutableShadowNode const *>(shadowNodeList.at(i + 1));
currentFrame.origin.y =
parentShadowNode->getLayoutMetrics().frame.size.height -
currentFrame.size.height - currentFrame.origin.y;
}

if (Transform::isHorizontalInversion(transformation)) {
auto parentShadowNode =
traitCast<LayoutableShadowNode const *>(shadowNodeList.at(i + 1));
currentFrame.origin.x =
parentShadowNode->getLayoutMetrics().frame.size.width -
currentFrame.size.width - currentFrame.origin.x;
}

if (i != size - 1) {
auto parentShadowNode =
traitCast<LayoutableShadowNode const *>(shadowNodeList.at(i + 1));
auto contentOritinOffset = parentShadowNode->getContentOriginOffset();
if (Transform::isVerticalInversion(transformation)) {
contentOritinOffset.y = -contentOritinOffset.y;
}
if (Transform::isHorizontalInversion(transformation)) {
contentOritinOffset.x = -contentOritinOffset.x;
}
currentFrame.origin += contentOritinOffset;
}

transformation = transformation * currentShadowNode->getTransform();
}

transformedFrames[i] = currentFrame;
}

return transformedFrames;
}

LayoutableShadowNode::LayoutableShadowNode(
ShadowNodeFragment const &fragment,
ShadowNodeFamily::Shared const &family,
Expand All @@ -34,6 +88,8 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
ShadowNodeFamily const &descendantNodeFamily,
LayoutableShadowNode const &ancestorNode,
LayoutInspectingPolicy policy) {
// Prelude.

if (&descendantNodeFamily == &ancestorNode.getFamily()) {
// Layout metrics of a node computed relatively to the same node are equal
// to `transform`-ed layout metrics of the node with zero `origin`.
Expand All @@ -53,10 +109,12 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
return EmptyLayoutMetrics;
}

// ------------------------------

// Step 1.
// Creating a list of nodes that form a chain from the descender node to
// ancestor node inclusively.
auto shadowNodeList = butter::small_vector<ShadowNode const *, 16>{};
auto shadowNodeList = LayoutableSmallVector<ShadowNode const *>{};

// Finding the measured node.
// The last element in the `AncestorList` is a pair of a parent of the node
Expand All @@ -81,6 +139,8 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
}
}

// ------------------------------

// Step 2.
// Computing the initial size of the measured node.
auto descendantLayoutableNode =
Expand All @@ -90,6 +150,9 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
return EmptyLayoutMetrics;
}

// ------------------------------

auto transformedFrames = calculateTransformedFrames(shadowNodeList, policy);
auto layoutMetrics = descendantLayoutableNode->getLayoutMetrics();
auto &resultFrame = layoutMetrics.frame;
resultFrame.origin = {0, 0};
Expand All @@ -105,7 +168,7 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
return EmptyLayoutMetrics;
}

auto currentFrame = currentShadowNode->getLayoutMetrics().frame;
auto currentFrame = transformedFrames[i];
if (i == size - 1) {
// If it's the last element, its origin is irrelevant.
currentFrame.origin = {0, 0};
Expand All @@ -122,12 +185,10 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics(
}

resultFrame.origin += currentFrame.origin;

if (i != 0 && policy.includeTransform) {
resultFrame.origin += currentShadowNode->getContentOriginOffset();
}
}

// ------------------------------

return layoutMetrics;
}

Expand Down
Loading

0 comments on commit 64528e5

Please sign in to comment.