LibWeb: Draw canvas arcs and ellipses correctly when radius is zero

In this case, we should just draw a line from the last point in the
path to the start point. Previously, a division by zero caused nothing
to be drawn.
This commit is contained in:
Tim Ledbetter 2025-10-22 14:32:04 +01:00 committed by Jelle Raaijmakers
parent 865699066e
commit 2fd424ccb6
Notes: github-actions[bot] 2025-10-22 14:11:08 +00:00
3 changed files with 55 additions and 4 deletions

View file

@ -93,6 +93,7 @@ void CanvasPath::bezier_curve_to(double cp1x, double cp1y, double cp2x, double c
Gfx::FloatPoint { cp1x, cp1y }, Gfx::FloatPoint { cp2x, cp2y }, Gfx::FloatPoint { x, y });
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-arc
WebIDL::ExceptionOr<void> CanvasPath::arc(float x, float y, float radius, float start_angle, float end_angle, bool counter_clockwise)
{
if (radius < 0 && isfinite(radius))
@ -113,6 +114,18 @@ WebIDL::ExceptionOr<void> CanvasPath::ellipse(float x, float y, float radius_x,
if (radius_y < 0)
return WebIDL::IndexSizeError::create(m_self->realm(), Utf16String::formatted("The minor-axis radius provided ({}) is negative.", radius_y));
auto add_line_to_start_point = [this](Gfx::FloatPoint const& start_point) {
if (!m_path.is_empty())
m_path.line_to(start_point);
else
m_path.move_to(start_point);
};
if (radius_x == 0 || radius_y == 0) {
add_line_to_start_point(Gfx::FloatPoint { x, y });
return {};
}
// "If counterclockwise is false and endAngle startAngle is greater than or equal to 2π,
// or, if counterclockwise is true and startAngle endAngle is greater than or equal to 2π,
// then the arc is the whole circumference of this ellipse"
@ -177,10 +190,7 @@ WebIDL::ExceptionOr<void> CanvasPath::ellipse(float x, float y, float radius_x,
delta_theta += AK::Pi<float> * 2;
// 3. If canvasPath's path has any subpaths, then add a straight line from the last point in the subpath to the start point of the arc.
if (!m_path.is_empty())
m_path.line_to(start_point);
else
m_path.move_to(start_point);
add_line_to_start_point(start_point);
// 4. Add the start and end points of the arc to the subpath, and connect them with an arc.
m_path.elliptical_arc_to(

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass arc() with zero radius draws a line to the start point

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>Canvas test: 2d.path.arc.zeroradius</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="../../../../html/canvas/resources/canvas-tests.css">
<body class="show_output">
<h1>2d.path.arc.zeroradius</h1>
<p class="desc">arc() with zero radius draws a line to the start point</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="../../../../images/green-100x50.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("arc() with zero radius draws a line to the start point");
_addTest(function(canvas, ctx) {
ctx.fillStyle = '#f00'
ctx.fillRect(0, 0, 100, 50);
ctx.lineWidth = 50;
ctx.strokeStyle = '#0f0';
ctx.beginPath();
ctx.moveTo(0, 25);
ctx.arc(200, 25, 0, 0, Math.PI, true);
ctx.stroke();
_assertPixel(canvas, 50,25, 0,255,0,255);
});
</script>