Summary: X-link: https://github.com/facebook/react-native/pull/41391 Pull Request resolved: https://github.com/facebook/yoga/pull/1461 Converts usages of `YGEdge` within internal APIs to `yoga::Edge` scoped enum. With the exception of YGUnit which is in its own state of transition, this is the last public yoga enum to need to be moved to scoped enum form for usages internal to the Yoga public API. Changelog: [internal] Reviewed By: rshest Differential Revision: D51152779 fbshipit-source-id: 06554f67bfd7709cbc24fdd9a5474e897e9e95d8
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(Edge::Left);
|
|
const double nodeTop = node->getLayout().position(Edge::Top);
|
|
|
|
const double nodeWidth = node->getLayout().dimension(Dimension::Width);
|
|
const double nodeHeight = node->getLayout().dimension(Dimension::Height);
|
|
|
|
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),
|
|
Edge::Left);
|
|
|
|
node->setLayoutPosition(
|
|
roundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
|
|
Edge::Top);
|
|
|
|
// 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),
|
|
Dimension::Width);
|
|
|
|
node->setLayoutDimension(
|
|
roundValueToPixelGrid(
|
|
absoluteNodeBottom,
|
|
pointScaleFactor,
|
|
(textRounding && hasFractionalHeight),
|
|
(textRounding && !hasFractionalHeight)) -
|
|
roundValueToPixelGrid(
|
|
absoluteNodeTop, pointScaleFactor, false, textRounding),
|
|
Dimension::Height);
|
|
}
|
|
|
|
for (yoga::Node* child : node->getChildren()) {
|
|
roundLayoutResultsToPixelGrid(child, absoluteNodeLeft, absoluteNodeTop);
|
|
}
|
|
}
|
|
|
|
} // namespace facebook::yoga
|