LibWeb: Add and use the "snap a length as a border width" algorithm

Previously, we always rounded border-widths up when converting them to
device pixels. However, the spec asks us to follow a specific algorithm
to "snap" these values, so that the computed value is snapped.

The difference from before, is that widths of between 0 and 1 device
pixels are rounded up to 1, and and values larger than 1 are rounded
down.
This commit is contained in:
Sam Atkins 2023-07-30 16:15:38 +01:00 committed by Sam Atkins
parent 5ee1b7db7c
commit 6038e36250
3 changed files with 42 additions and 1 deletions

View file

@ -0,0 +1,5 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x204 children: not-inline
BlockContainer <div.a> at (9,9) content-size 100x100 children: not-inline
BlockContainer <div.b> at (9,111) content-size 100x100 children: not-inline

View file

@ -0,0 +1,14 @@
<style>
div {
width: 100px;
height: 100px;
}
/* Both of these border-widths should snap to 1px. */
.a {
border: 1.8px solid black;
}
.b {
border: 0.2px solid black;
}
</style><div class="a"></div><div class="b"></div>

View file

@ -289,6 +289,28 @@ NodeWithStyle::NodeWithStyle(DOM::Document& document, DOM::Node* node, CSS::Comp
m_font = Platform::FontPlugin::the().default_font();
}
// https://www.w3.org/TR/css-values-4/#snap-a-length-as-a-border-width
static CSSPixels snap_a_length_as_a_border_width(double device_pixels_per_css_pixel, CSSPixels length)
{
// 1. Assert: len is non-negative.
VERIFY(length >= 0);
// 2. If len is an integer number of device pixels, do nothing.
auto device_pixels = length.to_double() * device_pixels_per_css_pixel;
if (device_pixels == trunc(device_pixels))
return length;
// 3. If len is greater than zero, but less than 1 device pixel, round len up to 1 device pixel.
if (device_pixels > 0 && device_pixels < 1)
return 1 / device_pixels_per_css_pixel;
// 4. If len is greater than 1 device pixel, round it down to the nearest integer number of device pixels.
if (device_pixels > 1)
return floor(device_pixels) / device_pixels_per_css_pixel;
return length;
}
void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
{
auto& computed_values = static_cast<CSS::MutableComputedValues&>(m_computed_values);
@ -676,7 +698,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
VERIFY_NOT_REACHED();
};
border.width = resolve_border_width();
border.width = snap_a_length_as_a_border_width(document().page()->client().device_pixels_per_css_pixel(), resolve_border_width());
}
};