mirror of
https://github.com/RGBCube/serenity
synced 2025-07-22 19:07:34 +00:00
LibWeb: Add propper rounding to PixelUnits::operator*
Also moves related constants into the class to make them accessible for tests.
This commit is contained in:
parent
4896ba11dc
commit
f9fc0505fb
3 changed files with 36 additions and 6 deletions
|
@ -39,6 +39,17 @@ TEST_CASE(multiplication1)
|
||||||
CSSPixels b(4);
|
CSSPixels b(4);
|
||||||
CSSPixels c = a * b;
|
CSSPixels c = a * b;
|
||||||
EXPECT_EQ(c, CSSPixels(12));
|
EXPECT_EQ(c, CSSPixels(12));
|
||||||
|
|
||||||
|
// Temporary overflow
|
||||||
|
a = CSSPixels::from_raw(0xFFFF'FFFF >> (CSSPixels::fractional_bits + 1));
|
||||||
|
b = 1;
|
||||||
|
EXPECT_EQ((a * b), a);
|
||||||
|
|
||||||
|
// Rounding
|
||||||
|
a = CSSPixels::from_raw(0b01'000001);
|
||||||
|
b = CSSPixels::from_raw(0b01'100000);
|
||||||
|
EXPECT_EQ(a * b, CSSPixels(a.to_double() * b.to_double()));
|
||||||
|
EXPECT_EQ(a * -b, CSSPixels(a.to_double() * -b.to_double()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(addition2)
|
TEST_CASE(addition2)
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
|
||||||
static i32 const fractional_bits = 6;
|
|
||||||
static constexpr i32 fixed_point_denominator = 1 << fractional_bits;
|
|
||||||
|
|
||||||
CSSPixels::CSSPixels(int value)
|
CSSPixels::CSSPixels(int value)
|
||||||
{
|
{
|
||||||
m_value = value * fixed_point_denominator;
|
m_value = value * fixed_point_denominator;
|
||||||
|
@ -103,9 +100,26 @@ CSSPixels CSSPixels::operator-(CSSPixels const& other) const
|
||||||
|
|
||||||
CSSPixels CSSPixels::operator*(CSSPixels const& other) const
|
CSSPixels CSSPixels::operator*(CSSPixels const& other) const
|
||||||
{
|
{
|
||||||
CSSPixels result;
|
i64 value = raw_value();
|
||||||
result.set_raw_value((static_cast<i64>(raw_value()) * other.raw_value()) >> fractional_bits);
|
value *= other.raw_value();
|
||||||
return result;
|
|
||||||
|
int int_value = AK::clamp_to_int(value >> fractional_bits);
|
||||||
|
|
||||||
|
// Rounding:
|
||||||
|
// If last bit cut off was 1:
|
||||||
|
if (value & (1u << (fractional_bits - 1))) {
|
||||||
|
// If the bit after was 1 as well
|
||||||
|
if (value & (radix_mask >> 2u)) {
|
||||||
|
// We need to round away from 0
|
||||||
|
int_value = Checked<int>::saturating_add(int_value, 1);
|
||||||
|
} else {
|
||||||
|
// Otherwise we round to the next even value
|
||||||
|
// Which means we add the least significant bit of the raw integer value
|
||||||
|
int_value = Checked<int>::saturating_add(int_value, int_value & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return from_raw(int_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSPixels CSSPixels::operator/(CSSPixels const& other) const
|
CSSPixels CSSPixels::operator/(CSSPixels const& other) const
|
||||||
|
|
|
@ -52,6 +52,11 @@ constexpr DevicePixels operator%(DevicePixels left, T right) { return left.value
|
||||||
/// See https://www.w3.org/TR/css-values-3/#reference-pixel
|
/// See https://www.w3.org/TR/css-values-3/#reference-pixel
|
||||||
class CSSPixels {
|
class CSSPixels {
|
||||||
public:
|
public:
|
||||||
|
static constexpr i32 fractional_bits = 6;
|
||||||
|
static constexpr i32 fixed_point_denominator = 1 << fractional_bits;
|
||||||
|
|
||||||
|
static constexpr i32 radix_mask = fixed_point_denominator - 1;
|
||||||
|
|
||||||
CSSPixels() = default;
|
CSSPixels() = default;
|
||||||
CSSPixels(int value);
|
CSSPixels(int value);
|
||||||
CSSPixels(unsigned int value);
|
CSSPixels(unsigned int value);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue