Add rounding to the pixel grid to Yoga

Reviewed By: emilsjolander

Differential Revision: D4565980

fbshipit-source-id: 9700f6d6ed147f82b19f230fbff2e9ccbd625b25
This commit is contained in:
Georgiy Kassabli 2017-02-24 09:45:31 -08:00 committed by Facebook Github Bot
parent 7f6f964e18
commit 387ec8ce37
2 changed files with 55 additions and 11 deletions

View File

@ -3216,18 +3216,58 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
return (needToVisitNode || cachedResults == NULL);
}
static void YGRoundToPixelGrid(const YGNodeRef node) {
const float fractialLeft =
node->layout.position[YGEdgeLeft] - floorf(node->layout.position[YGEdgeLeft]);
const float fractialTop =
node->layout.position[YGEdgeTop] - floorf(node->layout.position[YGEdgeTop]);
node->layout.dimensions[YGDimensionWidth] =
roundf(fractialLeft + node->layout.dimensions[YGDimensionWidth]) - roundf(fractialLeft);
node->layout.dimensions[YGDimensionHeight] =
roundf(fractialTop + node->layout.dimensions[YGDimensionHeight]) - roundf(fractialTop);
static float gPointScaleFactor = 1.0;
node->layout.position[YGEdgeLeft] = roundf(node->layout.position[YGEdgeLeft]);
node->layout.position[YGEdgeTop] = roundf(node->layout.position[YGEdgeTop]);
void YGSetPointScaleFactor(float pixelsInPoint) {
YG_ASSERT(pixelsInPoint >= 0.0, "Scale factor should not be less than zero");
// We store points for Pixel as we will use it for rounding
if (pixelsInPoint == 0.0) {
// Zero is used to skip rounding
gPointScaleFactor = 0.0;
} else {
gPointScaleFactor = 1.0 / pixelsInPoint;
}
}
static void YGRoundToPixelGrid(const YGNodeRef node) {
if (gPointScaleFactor == 0.0) {
return;
}
const float nodeLeft = node->layout.position[YGEdgeLeft];
const float nodeTop = node->layout.position[YGEdgeTop];
// To round correctly to the pixel grid, first we calculate left and top coordinates
float fractialLeft = fmodf(nodeLeft, gPointScaleFactor);
float fractialTop = fmodf(nodeTop, gPointScaleFactor);
float roundedLeft = nodeLeft - fractialLeft;
float roundedTop = nodeTop - fractialTop;
// To do the actual rounding we check if leftover fraction is bigger or equal than half of the grid step
if (fractialLeft >= gPointScaleFactor / 2.0) {
roundedLeft += gPointScaleFactor;
fractialLeft -= gPointScaleFactor;
}
if (fractialTop >= gPointScaleFactor / 2.0) {
roundedTop += gPointScaleFactor;
fractialTop -= gPointScaleFactor;
}
node->layout.position[YGEdgeLeft] = roundedLeft;
node->layout.position[YGEdgeTop] = roundedTop;
// Now we round width and height in the same way accounting for fractial leftovers from rounding position
const float adjustedWidth = fractialLeft + node->layout.dimensions[YGDimensionWidth];
const float adjustedHeight = fractialTop + node->layout.dimensions[YGDimensionHeight];
float roundedWidth = adjustedWidth - fmodf(adjustedWidth, gPointScaleFactor);
float roundedHeight = adjustedHeight - fmodf(adjustedHeight, gPointScaleFactor);
if (adjustedWidth - roundedWidth >= gPointScaleFactor / 2.0) {
roundedWidth += gPointScaleFactor;
}
if (adjustedHeight - roundedHeight >= gPointScaleFactor / 2.0) {
roundedHeight += gPointScaleFactor;
}
node->layout.dimensions[YGDimensionWidth] = roundedWidth;
node->layout.dimensions[YGDimensionHeight] = roundedHeight;
const uint32_t childCount = YGNodeListCount(node->children);
for (uint32_t i = 0; i < childCount; i++) {

View File

@ -219,6 +219,10 @@ YG_NODE_LAYOUT_EDGE_PROPERTY(float, Padding);
WIN_EXPORT void YGSetLogger(YGLogger logger);
WIN_EXPORT void YGLog(YGLogLevel level, const char *message, ...);
// Set this to number of pixels in 1 point to round calculation results
// If you want to avoid rounding - set PointScaleFactor to 0
WIN_EXPORT void YGSetPointScaleFactor(float pixelsInPoint);
WIN_EXPORT void YGSetExperimentalFeatureEnabled(YGExperimentalFeature feature, bool enabled);
WIN_EXPORT bool YGIsExperimentalFeatureEnabled(YGExperimentalFeature feature);