LibWeb: Fix border painting with border-radius and zero-width sides

When joined border width is zero width, then the midpoint
of the joined corner is no longer need to be computed
anymore. Just set the mid point to be the endpoint of the
corner.
This commit is contained in:
zhiyuang 2023-07-24 19:09:34 +08:00 committed by Andreas Kling
parent 8f7b269bf1
commit 94491ead67
2 changed files with 71 additions and 41 deletions

View file

@ -70,6 +70,22 @@
border-left: 20px solid blue;
}
.box-1-13 {
border-radius: 15px;
border-color: black;
border: 3px solid black;
border-top-width: 0;
border-bottom-width: 0;
}
.box-1-14 {
border-radius: 15px;
border-color: black;
border: 3px solid black;
border-left-width: 0;
border-right-width: 0;
}
.box-3 {
border: 1px solid black;
border-top-right-radius: 10px;
@ -418,6 +434,12 @@
<em>Four border with different colors</em>
<div class="box box-1-12"></div>
<br>
<em>Border radius with top and bottom zero width</em>
<div class="box box-1-13"></div>
<br>
<em>Border radius with left and right zero width</em>
<div class="box box-1-14"></div>
<br>
<em>top-left 10px</em>
<div class="box box-2"></div>
<br>

View file

@ -205,10 +205,22 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
}
};
auto compute_midpoint = [](int horizontal_radius, int vertical_radius) {
auto compute_midpoint = [&](int horizontal_radius, int vertical_radius, int joined_border_width) {
if (horizontal_radius == 0 && vertical_radius == 0) {
return Gfx::FloatPoint(0, 0);
}
if (joined_border_width == 0) {
switch (edge) {
case BorderEdge::Top:
case BorderEdge::Bottom:
return Gfx::FloatPoint(horizontal_radius, 0);
case BorderEdge::Right:
case BorderEdge::Left:
return Gfx::FloatPoint(0, vertical_radius);
default:
VERIFY_NOT_REACHED();
}
}
// FIXME: this middle point rule seems not exacly the same as main browsers
// compute the midpoint based on point whose tangent slope of 1
// https://math.stackexchange.com/questions/3325134/find-the-points-on-the-ellipse-where-the-slope-of-the-tangent-line-is-1
@ -235,17 +247,14 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
Gfx::FloatPoint joined_corner_endpoint_offset;
Gfx::FloatPoint opposite_joined_border_corner_offset;
if (borders_data.left.width == 0) {
joined_corner_endpoint_offset = Gfx::FloatPoint(-radius.horizontal_radius, radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius);
{
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius, joined_border_width.value());
joined_corner_endpoint_offset = Gfx::FloatPoint(-midpoint.x(), radius.vertical_radius - midpoint.y());
}
if (borders_data.right.width == 0) {
opposite_joined_border_corner_offset = Gfx::FloatPoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
{
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius, opposite_joined_border_width.value());
opposite_joined_border_corner_offset = Gfx::FloatPoint(midpoint.x(), opposite_radius.vertical_radius - midpoint.y());
}
@ -256,7 +265,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (joined_corner_has_inner_corner) {
Gfx::FloatPoint midpoint = compute_midpoint(
radius.horizontal_radius - joined_border_width.value(),
radius.vertical_radius - device_pixel_width.value());
radius.vertical_radius - device_pixel_width.value(),
joined_border_width.value());
Gfx::FloatPoint inner_corner_endpoint_offset = Gfx::FloatPoint(
-midpoint.x(),
radius.vertical_radius - device_pixel_width.value() - midpoint.y());
@ -272,7 +282,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (opposite_joined_corner_has_inner_corner) {
Gfx::FloatPoint midpoint = compute_midpoint(
opposite_radius.horizontal_radius - opposite_joined_border_width.value(),
opposite_radius.vertical_radius - device_pixel_width.value());
opposite_radius.vertical_radius - device_pixel_width.value(),
opposite_joined_border_width.value());
Gfx::FloatPoint inner_corner_endpoint_offset = Gfx::FloatPoint(
midpoint.x(),
opposite_radius.vertical_radius - device_pixel_width.value() - midpoint.y());
@ -305,17 +316,14 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
Gfx::FloatPoint joined_corner_endpoint_offset;
Gfx::FloatPoint opposite_joined_border_corner_offset;
if (borders_data.top.width == 0) {
joined_corner_endpoint_offset = Gfx::FloatPoint(-radius.horizontal_radius, -radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius);
{
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius, joined_border_width.value());
joined_corner_endpoint_offset = Gfx::FloatPoint(midpoint.x() - radius.horizontal_radius, -midpoint.y());
}
if (borders_data.bottom.width == 0) {
opposite_joined_border_corner_offset = Gfx::FloatPoint(-opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
{
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius, opposite_joined_border_width.value());
opposite_joined_border_corner_offset = Gfx::FloatPoint(midpoint.x() - opposite_radius.horizontal_radius, midpoint.y());
}
@ -326,7 +334,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (joined_corner_has_inner_corner) {
auto midpoint = compute_midpoint(
radius.horizontal_radius - device_pixel_width.value(),
radius.vertical_radius - joined_border_width.value());
radius.vertical_radius - joined_border_width.value(),
joined_border_width.value());
Gfx::FloatPoint inner_corner = Gfx::FloatPoint(
-(radius.horizontal_radius - midpoint.x() - device_pixel_width.value()),
-midpoint.y());
@ -340,7 +349,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (opposite_joined_corner_has_inner_corner) {
auto midpoint = compute_midpoint(
opposite_radius.horizontal_radius - device_pixel_width.value(),
opposite_radius.vertical_radius - opposite_joined_border_width.value());
opposite_radius.vertical_radius - opposite_joined_border_width.value(),
opposite_joined_border_width.value());
Gfx::FloatPoint inner_corner = Gfx::FloatPoint(
-(opposite_radius.horizontal_radius - midpoint.x() - device_pixel_width.value()),
midpoint.y());
@ -371,17 +381,14 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
Gfx::FloatPoint joined_corner_endpoint_offset;
Gfx::FloatPoint opposite_joined_border_corner_offset;
if (borders_data.right.width == 0) {
joined_corner_endpoint_offset = Gfx::FloatPoint(radius.horizontal_radius, -radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius);
{
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius, joined_border_width.value());
joined_corner_endpoint_offset = Gfx::FloatPoint(midpoint.x(), midpoint.y() - radius.vertical_radius);
}
if (borders_data.left.width == 0) {
opposite_joined_border_corner_offset = Gfx::FloatPoint(-opposite_radius.horizontal_radius, -opposite_radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
{
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius, opposite_joined_border_width.value());
opposite_joined_border_corner_offset = Gfx::FloatPoint(-midpoint.x(), midpoint.y() - opposite_radius.vertical_radius);
}
@ -392,7 +399,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (joined_corner_has_inner_corner) {
auto midpoint = compute_midpoint(
radius.horizontal_radius - joined_border_width.value(),
radius.vertical_radius - device_pixel_width.value());
radius.vertical_radius - device_pixel_width.value(),
joined_border_width.value());
Gfx::FloatPoint inner_corner = Gfx::FloatPoint(midpoint.x(), -(radius.vertical_radius - midpoint.y() - device_pixel_width.value()));
points.append(Gfx::FloatPoint(rect.top_right().to_type<int>()) + inner_corner);
points.append(Gfx::FloatPoint(rect.top_right().to_type<int>()));
@ -404,7 +412,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (opposite_joined_corner_has_inner_corner) {
auto midpoint = compute_midpoint(
opposite_radius.horizontal_radius - opposite_joined_border_width.value(),
opposite_radius.vertical_radius - device_pixel_width.value());
opposite_radius.vertical_radius - device_pixel_width.value(),
opposite_joined_border_width.value());
Gfx::FloatPoint inner_corner = Gfx::FloatPoint(
-midpoint.x(),
-(opposite_radius.vertical_radius - midpoint.y() - device_pixel_width.value()));
@ -434,17 +443,14 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
Gfx::FloatPoint joined_corner_endpoint_offset;
Gfx::FloatPoint opposite_joined_border_corner_offset;
if (borders_data.bottom.width == 0) {
joined_corner_endpoint_offset = Gfx::FloatPoint(radius.horizontal_radius, radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius);
{
auto midpoint = compute_midpoint(radius.horizontal_radius, radius.vertical_radius, joined_border_width.value());
joined_corner_endpoint_offset = Gfx::FloatPoint(radius.horizontal_radius - midpoint.x(), midpoint.y());
}
if (borders_data.top.width == 0) {
opposite_joined_border_corner_offset = Gfx::FloatPoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
} else {
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius);
{
auto midpoint = compute_midpoint(opposite_radius.horizontal_radius, opposite_radius.vertical_radius, opposite_joined_border_width.value());
opposite_joined_border_corner_offset = Gfx::FloatPoint(opposite_radius.horizontal_radius - midpoint.x(), -midpoint.y());
}
@ -455,7 +461,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (joined_corner_has_inner_corner) {
auto midpoint = compute_midpoint(
radius.horizontal_radius - device_pixel_width.value(),
radius.vertical_radius - joined_border_width.value());
radius.vertical_radius - joined_border_width.value(),
joined_border_width.value());
Gfx::FloatPoint inner_corner = Gfx::FloatPoint(radius.horizontal_radius - device_pixel_width.value() - midpoint.x(), midpoint.y());
points.append(Gfx::FloatPoint(rect.bottom_right().to_type<int>()) + inner_corner);
points.append(Gfx::FloatPoint(rect.bottom_right().to_type<int>()));
@ -467,7 +474,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
if (opposite_joined_corner_has_inner_corner) {
auto midpoint = compute_midpoint(
opposite_radius.horizontal_radius - device_pixel_width.value(),
opposite_radius.vertical_radius - opposite_joined_border_width.value());
opposite_radius.vertical_radius - opposite_joined_border_width.value(),
opposite_joined_border_width.value());
Gfx::FloatPoint inner_corner = Gfx::FloatPoint(
opposite_radius.horizontal_radius - device_pixel_width.value() - midpoint.x(),
-midpoint.y());