Skip to content

Commit

Permalink
Fixing edge case issue in Yoga where text node was unnecessary rounde…
Browse files Browse the repository at this point in the history
…d down

Summary: There was an uncovered edge case where number close to the whole was forced to round down because it was considered non-whole and had forced flooring. This diff covers that + adds a bunch of test cases to cover rounding function

Reviewed By: emilsjolander

Differential Revision: D5465632

fbshipit-source-id: 57e11092a97eba5dd76daad15fa8619535ff9c1b
  • Loading branch information
Georgiy Kassabli authored and facebook-github-bot committed Jul 27, 2017
1 parent c938476 commit f45059e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
31 changes: 31 additions & 0 deletions tests/YGRoundingFunctionTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#include <gtest/gtest.h>

#include <yoga/Yoga.h>
#include <yoga/Yoga-internal.h>

TEST(YogaTest, rounding_value) {
// Test that whole numbers are rounded to whole despite ceil/floor flags
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.000001, 2.0, false, false));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.000001, 2.0, true, false));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.000001, 2.0, false, true));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.999999, 2.0, false, false));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.999999, 2.0, true, false));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.999999, 2.0, false, true));

// Test that numbers with fraction are rounded correctly accounting for ceil/floor flags
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.01, 2.0, false, false));
ASSERT_FLOAT_EQ(6.5, YGRoundValueToPixelGrid(6.01, 2.0, true, false));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.01, 2.0, false, true));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.99, 2.0, false, false));
ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.99, 2.0, true, false));
ASSERT_FLOAT_EQ(5.5, YGRoundValueToPixelGrid(5.99, 2.0, false, true));
}
19 changes: 19 additions & 0 deletions yoga/Yoga-internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#pragma once

YG_EXTERN_C_BEGIN

WIN_EXPORT float YGRoundValueToPixelGrid(const float value,
const float pointScaleFactor,
const bool forceCeil,
const bool forceFloor);

YG_EXTERN_C_END
9 changes: 7 additions & 2 deletions yoga/Yoga.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "YGNodeList.h"
#include "Yoga.h"
#include "Yoga-internal.h"

#ifdef _MSC_VER
#include <float.h>
Expand Down Expand Up @@ -3158,20 +3159,24 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureM
lastSize > size && (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
}

static float YGRoundValueToPixelGrid(const float value,
float YGRoundValueToPixelGrid(const float value,
const float pointScaleFactor,
const bool forceCeil,
const bool forceFloor) {
float scaledValue = value * pointScaleFactor;
float fractial = fmodf(scaledValue, 1.0);
if (YGFloatsEqual(fractial, 0)) {
// Still remove fractial as fractial could be extremely small.
// First we check if the value is already rounded
scaledValue = scaledValue - fractial;
} else if (YGFloatsEqual(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 + (fractial >= 0.5f ? 1.0 : 0);
}
return scaledValue / pointScaleFactor;
Expand Down

0 comments on commit f45059e

Please sign in to comment.