1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:27:45 +00:00

LibWeb: Fix border-radius corner overlap algorithm for zero-width boxes

Previously, the corner overlap algorithm implementation did not shrink
the border radii for zero width/height boxes, which resulted in
incorrect painting.

With this the implementation is updated to more closely follow the spec
steps, which naturally handles the zero width/height case. This makes
use of the `CSSPixelFraction` class for lossless comparison and
multiplication of the scaling factor for the radii.

Co-authored-by: Zaggy1024 <Zaggy1024@gmail.com>
This commit is contained in:
MacDue 2023-08-25 00:36:43 +01:00 committed by Alexander Kalenik
parent 8cd1f65507
commit 2876e2f58e

View file

@ -35,24 +35,34 @@ BorderRadiiData normalized_border_radii_data(Layout::Node const& node, CSSPixelR
top_right_radius_px.vertical_radius = top_right_radius.vertical_radius.to_px(node, rect.height());
// Scale overlapping curves according to https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
CSSPixels f = 1;
if (rect.width() > 0) {
f = max(f, (top_left_radius_px.horizontal_radius + top_right_radius_px.horizontal_radius) / rect.width());
f = max(f, (bottom_left_radius_px.horizontal_radius + bottom_right_radius_px.horizontal_radius) / rect.width());
}
if (rect.height() > 0) {
f = max(f, (top_right_radius_px.vertical_radius + bottom_right_radius_px.vertical_radius) / rect.height());
f = max(f, (top_left_radius_px.vertical_radius + bottom_left_radius_px.vertical_radius) / rect.height());
}
// Let f = min(Li/Si), where i ∈ {top, right, bottom, left},
// Si is the sum of the two corresponding radii of the corners on side i,
// and Ltop = Lbottom = the width of the box, and Lleft = Lright = the height of the box.
auto l_top = rect.width();
auto l_bottom = l_top;
auto l_left = rect.height();
auto l_right = l_left;
auto s_top = (top_left_radius_px.horizontal_radius + top_right_radius_px.horizontal_radius);
auto s_right = (top_right_radius_px.vertical_radius + bottom_right_radius_px.vertical_radius);
auto s_bottom = (bottom_left_radius_px.horizontal_radius + bottom_right_radius_px.horizontal_radius);
auto s_left = (top_left_radius_px.vertical_radius + bottom_left_radius_px.vertical_radius);
CSSPixelFraction f = 1;
f = min(f, l_top / s_top);
f = min(f, l_right / s_right);
f = min(f, l_bottom / s_bottom);
f = min(f, l_left / s_left);
top_left_radius_px.horizontal_radius /= f;
top_left_radius_px.vertical_radius /= f;
top_right_radius_px.horizontal_radius /= f;
top_right_radius_px.vertical_radius /= f;
bottom_right_radius_px.horizontal_radius /= f;
bottom_right_radius_px.vertical_radius /= f;
bottom_left_radius_px.horizontal_radius /= f;
bottom_left_radius_px.vertical_radius /= f;
// If f < 1, then all corner radii are reduced by multiplying them by f.
if (f < 1) {
top_left_radius_px.horizontal_radius *= f;
top_left_radius_px.vertical_radius *= f;
top_right_radius_px.horizontal_radius *= f;
top_right_radius_px.vertical_radius *= f;
bottom_right_radius_px.horizontal_radius *= f;
bottom_right_radius_px.vertical_radius *= f;
bottom_left_radius_px.horizontal_radius *= f;
bottom_left_radius_px.vertical_radius *= f;
}
return BorderRadiiData { top_left_radius_px, top_right_radius_px, bottom_right_radius_px, bottom_left_radius_px };
}