Compare commits

...

5 commits

Author SHA1 Message Date
Lucas Chollet
80c37b10bd
Merge d820fde70a into 63a5717bc7 2024-11-20 16:09:04 -05:00
Lucas CHOLLET
d820fde70a LibWeb/CSS: Use double in CSSHWB::to_color()
See previous the commit description for more details about the floating
points operations.

The hwb test cases in `css-color-functions` are now rendered identically
to what firefox does (I haven't checked the others tests, but they
aren't affected by this commit).
2024-11-18 18:59:50 -05:00
Lucas CHOLLET
4099215e29 LibWeb: Make CSSColorValue resolvers return a double
Without this change the math in `CSSHWB::to_color()` is lacking some
precision to generate the correct value to hand to `Color::from_hsv()`.

More precisely, when converting `hwb(120 20 30)`, the HSV's value would
be calculated as `1 - .3`. However, it turns out that `1 - .3f != .7f`
and `1 - .3f` gives bad results down the road in `Color::from_hsv()`.

This example actually only requires `resolve_with_reference_value()` to
return a double. I changed the two others for symmetry.
2024-11-18 18:59:50 -05:00
Lucas CHOLLET
71fddcf4c7 LibGfx: Round values in Color::with_opacity()
`svg-gradient-userSpaceOnUse` is now rendered to something closer to
what firefox does, so it is at least some progress.
2024-11-18 18:59:47 -05:00
Lucas CHOLLET
a20498f5fd LibGfx: Round values in Color::from_hsv() 2024-11-18 18:39:48 -05:00
9 changed files with 48 additions and 13 deletions

View file

@ -400,7 +400,8 @@ public:
constexpr Color with_opacity(float opacity) const
{
return with_alpha(alpha() * opacity);
VERIFY(opacity >= 0 && opacity <= 1);
return with_alpha(static_cast<u8>(round(alpha() * opacity)));
}
constexpr Color darkened(float amount = 0.5f) const
@ -549,9 +550,9 @@ public:
break;
}
u8 out_r = (u8)(r * 255);
u8 out_g = (u8)(g * 255);
u8 out_b = (u8)(b * 255);
auto out_r = static_cast<u8>(round(r * 255));
auto out_g = static_cast<u8>(round(g * 255));
auto out_b = static_cast<u8>(round(b * 255));
return Color(out_r, out_g, out_b);
}

View file

@ -45,7 +45,7 @@ ValueComparingNonnullRefPtr<CSSColorValue> CSSColorValue::create_from_color(Colo
return make_rgb_color(color);
}
Optional<float> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
Optional<double> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
{
// <number> | <angle> | none
auto normalized = [](double number) {
@ -67,11 +67,11 @@ Optional<float> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
return {};
}
Optional<float> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value)
Optional<double> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value)
{
// <percentage> | <number> | none
auto normalize_percentage = [one_hundred_percent_value](Percentage const& percentage) {
return static_cast<float>(percentage.as_fraction()) * one_hundred_percent_value;
return percentage.as_fraction() * one_hundred_percent_value;
};
if (style_value.is_percentage())
@ -94,7 +94,7 @@ Optional<float> CSSColorValue::resolve_with_reference_value(CSSStyleValue const&
return {};
}
Optional<float> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value)
Optional<double> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value)
{
// <number> | <percentage> | none
auto normalized = [](double number) {

View file

@ -48,9 +48,9 @@ protected:
{
}
static Optional<float> resolve_hue(CSSStyleValue const&);
static Optional<float> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
static Optional<float> resolve_alpha(CSSStyleValue const&);
static Optional<double> resolve_hue(CSSStyleValue const&);
static Optional<double> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
static Optional<double> resolve_alpha(CSSStyleValue const&);
private:
ColorType m_color_type;

View file

@ -25,8 +25,8 @@ Color CSSHWB::to_color(Optional<Layout::NodeWithStyle const&>) const
return Color(gray, gray, gray, to_byte(alpha_val));
}
float value = 1 - b_val;
float saturation = 1 - (w_val / value);
auto value = 1 - b_val;
auto saturation = 1 - (w_val / value);
return Color::from_hsv(h_val, saturation, value).with_opacity(alpha_val);
}

View file

@ -21,3 +21,10 @@ TEST_CASE(all_green)
EXPECT_EQ(Color(Color::NamedColor::Green), Color::from_xyz50(0.385152, 0.716887, 0.097081));
EXPECT_EQ(Color(Color::NamedColor::Green), Color::from_xyz65(0.357584, 0.715169, 0.119195));
}
TEST_CASE(hsv)
{
EXPECT_EQ(Color(51, 179, 51), Color::from_hsv(120, 0.714285714, .7));
EXPECT_EQ(Color(51, 179, 51, 128), Color::from_hsv(120, 0.714285714, .7).with_opacity(0.5));
EXPECT_EQ(Color(87, 128, 77), Color::from_hsv(108, 0.4, .5));
}

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Color 4: CSS Color 4: hwb</title>
<style>
.test { background-color: rgb(20% 70% 20%); width: 12em; height: 12em; } /* hwb(120 20% 30%) converted to sRGB */
</style>
<body>
<p>Test passes if you see a single square, and not two rectangles of different colors.</p>
<div class="test"></div>
</body>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Color 4: hwb</title>
<link rel="author" title="Sam Weinig" href="mailto:weinig@apple.com">
<link rel="help" href="https://drafts.csswg.org/css-color-4/#the-hwb-notation">
<link rel="match" href="../../../../expected/wpt-import/css/css-color/hwb-004-ref.html">
<meta name="assert" content="hwb with no alpha">
<style>
.test { background-color: red; width: 12em; height: 6em; margin-top: 0; }
.ref { background-color: rgb(20% 70% 20%); width: 12em; height: 6em; margin-bottom: 0; } /* hwb(120 20% 30%) converted to sRGB */
.test { background-color: hwb(120 20% 30%); }
</style>
<body>
<p>Test passes if you see a single square, and not two rectangles of different colors.</p>
<div class="ref"></div>
<div class="test"></div>
</body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB