New round-to-pixel-grid algorithm that fixes possible subpixel gaps between sibling nodes

Reviewed By: emilsjolander

Differential Revision: D4941266

fbshipit-source-id: 07500f5cc93c628219500e9e07291438e9d5d36c
This commit is contained in:
Valentin Shergin 2017-04-25 17:29:27 -07:00 committed by Facebook Github Bot
parent 513da6fcf2
commit a8fa904179
1 changed files with 22 additions and 32 deletions

View File

@ -3293,49 +3293,39 @@ void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInP
}
}
static void YGRoundToPixelGrid(const YGNodeRef node, const float pointScaleFactor) {
static float YGRoundValueToPixelGrid(const float value, const float pointScaleFactor) {
float fractial = fmodf(value, pointScaleFactor);
return value - fractial + (fractial >= pointScaleFactor / 2.0f ? pointScaleFactor : 0);
}
static void YGRoundToPixelGrid(const YGNodeRef node, const float pointScaleFactor, const float absoluteLeft, const float absoluteTop) {
if (pointScaleFactor == 0.0f) {
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, pointScaleFactor);
float fractialTop = fmodf(nodeTop, pointScaleFactor);
float roundedLeft = nodeLeft - fractialLeft;
float roundedTop = nodeTop - fractialTop;
const float nodeWidth = node->layout.dimensions[YGDimensionWidth];
const float nodeHeight = node->layout.dimensions[YGDimensionHeight];
// To do the actual rounding we check if leftover fraction is bigger or equal than half of the grid step
if (fractialLeft >= pointScaleFactor / 2.0f) {
roundedLeft += pointScaleFactor;
fractialLeft -= pointScaleFactor;
}
if (fractialTop >= pointScaleFactor / 2.0f) {
roundedTop += pointScaleFactor;
fractialTop -= pointScaleFactor;
}
node->layout.position[YGEdgeLeft] = roundedLeft;
node->layout.position[YGEdgeTop] = roundedTop;
const float absoluteNodeLeft = absoluteLeft + nodeLeft;
const float absoluteNodeTop = absoluteTop + nodeTop;
// 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, pointScaleFactor);
float roundedHeight = adjustedHeight - fmodf(adjustedHeight, pointScaleFactor);
const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
if (adjustedWidth - roundedWidth >= pointScaleFactor / 2.0f) {
roundedWidth += pointScaleFactor;
}
if (adjustedHeight - roundedHeight >= pointScaleFactor / 2.0f) {
roundedHeight += pointScaleFactor;
}
node->layout.dimensions[YGDimensionWidth] = roundedWidth;
node->layout.dimensions[YGDimensionHeight] = roundedHeight;
node->layout.position[YGEdgeLeft] = YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor);
node->layout.position[YGEdgeTop] = YGRoundValueToPixelGrid(nodeTop, pointScaleFactor);
node->layout.dimensions[YGDimensionWidth] =
YGRoundValueToPixelGrid(absoluteNodeRight, pointScaleFactor) - YGRoundValueToPixelGrid(absoluteNodeLeft, pointScaleFactor);
node->layout.dimensions[YGDimensionHeight] =
YGRoundValueToPixelGrid(absoluteNodeBottom, pointScaleFactor) - YGRoundValueToPixelGrid(absoluteNodeTop, pointScaleFactor);
const uint32_t childCount = YGNodeListCount(node->children);
for (uint32_t i = 0; i < childCount; i++) {
YGRoundToPixelGrid(YGNodeGetChild(node, i), pointScaleFactor);
YGRoundToPixelGrid(YGNodeGetChild(node, i), pointScaleFactor, absoluteNodeLeft, absoluteNodeTop);
}
}
@ -3395,7 +3385,7 @@ void YGNodeCalculateLayout(const YGNodeRef node,
YGNodeSetPosition(node, node->layout.direction, parentWidth, parentHeight, parentWidth);
if (YGConfigIsExperimentalFeatureEnabled(node->config, YGExperimentalFeatureRounding)) {
YGRoundToPixelGrid(node, node->config->pointScaleFactor);
YGRoundToPixelGrid(node, node->config->pointScaleFactor, 0.0f, 0.0f);
}
if (gPrintTree) {