Summary: X-link: https://github.com/facebook/react-native/pull/39450 Pull Request resolved: https://github.com/facebook/yoga/pull/1383 This converts usages of YGNodeType to NodeType Reviewed By: rozele Differential Revision: D49269117 fbshipit-source-id: 27318279fe555c28c605625a160d5be781b662b8
133 lines
5.0 KiB
C++
133 lines
5.0 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include <yoga/Yoga.h>
|
|
|
|
#include <yoga/algorithm/PixelGrid.h>
|
|
#include <yoga/numeric/Comparison.h>
|
|
|
|
namespace facebook::yoga {
|
|
|
|
float roundValueToPixelGrid(
|
|
const double value,
|
|
const double pointScaleFactor,
|
|
const bool forceCeil,
|
|
const bool forceFloor) {
|
|
double scaledValue = value * pointScaleFactor;
|
|
// We want to calculate `fractial` such that `floor(scaledValue) = scaledValue
|
|
// - fractial`.
|
|
double fractial = fmod(scaledValue, 1.0);
|
|
if (fractial < 0) {
|
|
// This branch is for handling negative numbers for `value`.
|
|
//
|
|
// Regarding `floor` and `ceil`. Note that for a number x, `floor(x) <= x <=
|
|
// ceil(x)` even for negative numbers. Here are a couple of examples:
|
|
// - x = 2.2: floor( 2.2) = 2, ceil( 2.2) = 3
|
|
// - x = -2.2: floor(-2.2) = -3, ceil(-2.2) = -2
|
|
//
|
|
// Regarding `fmodf`. For fractional negative numbers, `fmodf` returns a
|
|
// negative number. For example, `fmodf(-2.2) = -0.2`. However, we want
|
|
// `fractial` to be the number such that subtracting it from `value` will
|
|
// give us `floor(value)`. In the case of negative numbers, adding 1 to
|
|
// `fmodf(value)` gives us this. Let's continue the example from above:
|
|
// - fractial = fmodf(-2.2) = -0.2
|
|
// - Add 1 to the fraction: fractial2 = fractial + 1 = -0.2 + 1 = 0.8
|
|
// - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3
|
|
++fractial;
|
|
}
|
|
if (yoga::inexactEquals(fractial, 0)) {
|
|
// First we check if the value is already rounded
|
|
scaledValue = scaledValue - fractial;
|
|
} else if (yoga::inexactEquals(fractial, 1.0)) {
|
|
scaledValue = scaledValue - fractial + 1.0;
|
|
} else if (forceCeil) {
|
|
// Next we check if we need to use forced rounding
|
|
scaledValue = scaledValue - fractial + 1.0;
|
|
} else if (forceFloor) {
|
|
scaledValue = scaledValue - fractial;
|
|
} else {
|
|
// Finally we just round the value
|
|
scaledValue = scaledValue - fractial +
|
|
(!std::isnan(fractial) &&
|
|
(fractial > 0.5 || yoga::inexactEquals(fractial, 0.5))
|
|
? 1.0
|
|
: 0.0);
|
|
}
|
|
return (std::isnan(scaledValue) || std::isnan(pointScaleFactor))
|
|
? YGUndefined
|
|
: (float)(scaledValue / pointScaleFactor);
|
|
}
|
|
|
|
void roundLayoutResultsToPixelGrid(
|
|
yoga::Node* const node,
|
|
const double absoluteLeft,
|
|
const double absoluteTop) {
|
|
const auto pointScaleFactor = node->getConfig()->getPointScaleFactor();
|
|
|
|
const double nodeLeft = node->getLayout().position[YGEdgeLeft];
|
|
const double nodeTop = node->getLayout().position[YGEdgeTop];
|
|
|
|
const double nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
|
|
const double nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
|
|
|
|
const double absoluteNodeLeft = absoluteLeft + nodeLeft;
|
|
const double absoluteNodeTop = absoluteTop + nodeTop;
|
|
|
|
const double absoluteNodeRight = absoluteNodeLeft + nodeWidth;
|
|
const double absoluteNodeBottom = absoluteNodeTop + nodeHeight;
|
|
|
|
if (pointScaleFactor != 0.0f) {
|
|
// If a node has a custom measure function we never want to round down its
|
|
// size as this could lead to unwanted text truncation.
|
|
const bool textRounding = node->getNodeType() == NodeType::Text;
|
|
|
|
node->setLayoutPosition(
|
|
roundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
|
|
YGEdgeLeft);
|
|
|
|
node->setLayoutPosition(
|
|
roundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
|
|
YGEdgeTop);
|
|
|
|
// We multiply dimension by scale factor and if the result is close to the
|
|
// whole number, we don't have any fraction To verify if the result is close
|
|
// to whole number we want to check both floor and ceil numbers
|
|
const bool hasFractionalWidth =
|
|
!yoga::inexactEquals(fmod(nodeWidth * pointScaleFactor, 1.0), 0) &&
|
|
!yoga::inexactEquals(fmod(nodeWidth * pointScaleFactor, 1.0), 1.0);
|
|
const bool hasFractionalHeight =
|
|
!yoga::inexactEquals(fmod(nodeHeight * pointScaleFactor, 1.0), 0) &&
|
|
!yoga::inexactEquals(fmod(nodeHeight * pointScaleFactor, 1.0), 1.0);
|
|
|
|
node->setLayoutDimension(
|
|
roundValueToPixelGrid(
|
|
absoluteNodeRight,
|
|
pointScaleFactor,
|
|
(textRounding && hasFractionalWidth),
|
|
(textRounding && !hasFractionalWidth)) -
|
|
roundValueToPixelGrid(
|
|
absoluteNodeLeft, pointScaleFactor, false, textRounding),
|
|
YGDimensionWidth);
|
|
|
|
node->setLayoutDimension(
|
|
roundValueToPixelGrid(
|
|
absoluteNodeBottom,
|
|
pointScaleFactor,
|
|
(textRounding && hasFractionalHeight),
|
|
(textRounding && !hasFractionalHeight)) -
|
|
roundValueToPixelGrid(
|
|
absoluteNodeTop, pointScaleFactor, false, textRounding),
|
|
YGDimensionHeight);
|
|
}
|
|
|
|
for (yoga::Node* child : node->getChildren()) {
|
|
roundLayoutResultsToPixelGrid(child, absoluteNodeLeft, absoluteNodeTop);
|
|
}
|
|
}
|
|
|
|
} // namespace facebook::yoga
|