Files
yoga/yoga/algorithm/PixelGrid.cpp
Nick Gerleman 9129a0af87 C++ style enums 2/N: NodeType (#1383)
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
2023-09-14 23:06:34 -07:00

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