Skip to content

Support round_rect() on Canvas#4161

Merged
freakboy3742 merged 9 commits intobeeware:mainfrom
corranwebster:canvas-round-rect
Feb 5, 2026
Merged

Support round_rect() on Canvas#4161
freakboy3742 merged 9 commits intobeeware:mainfrom
corranwebster:canvas-round-rect

Conversation

@corranwebster
Copy link
Copy Markdown
Contributor

@corranwebster corranwebster commented Feb 3, 2026

This implements support for the round_rect(x, y, w, h, radii) method of the HTML Canvas.

round_rect-full

I've tried to follow the behaviour of the HTML Canvas, where the radii can either be given as floats or objects with x and y attributes that give the x and y radii, and similarly the behaviour for providing lists of 1, 2, 3 or 4 corner radii (see https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-roundrect for the HTML specification). It should handle negative widths and heights and 0 radius corners as well.

The latter required a drive-by refactor for the ellipse method for Cocoa, iOS and GTK to avoid division by 0, but which also simplifies the code and makes it more general.

No backend implements round_rect in a compatible way with the HTML Canvas, so this is implemented entirely using existing primitive operations (move_to, line_to and ellipse) on the native contexts with common code in toga.widgets.canvas.geometry, which is possible since the native Context objects all share a compatible API (thanks to #4057).

Ref #3994.

This has a small intersection with the refactoring of the State object in #4159.

PR Checklist:

  • All new features have been tested
  • All new features have been documented
  • I have read the CONTRIBUTING.md file
  • I will abide by the code of conduct

@corranwebster corranwebster changed the title Add support for rounded rectangles to Canvases Add support for round_rect() to Canvas Feb 3, 2026
@corranwebster corranwebster changed the title Add support for round_rect() to Canvas Support round_rect() on Canvas Feb 3, 2026
@corranwebster
Copy link
Copy Markdown
Contributor Author

Going to close and re-open to see if I can trigger a successful iOS run.

@corranwebster
Copy link
Copy Markdown
Contributor Author

The tests on iOS passed before the timeout, so I think this is ready for review.

@corranwebster corranwebster marked this pull request as ready for review February 3, 2026 15:02
Copy link
Copy Markdown
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great (and +1 for literally implementing what the spec says); a couple of minor suggestions inline.

Comment thread core/src/toga/widgets/canvas/geometry.py Outdated
Comment on lines +295 to +300
def assert_get_round_rect_radii(w, h, radii, expected):
actual = get_round_rect_radii(w, h, radii)
assert actual == expected


def test_get_round_rect_radii():
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads like it should be a parameterized test (or two tests - one for good cases, and one for error cases), rather than one test validating all cases in sequence. That should also remove the need for the helper assertion (since it will only be used in one place).

"StrokeContext",
# Geometry
"arc_to_bezier",
"get_round_rect_radii",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be exposed as public API? It's definitely a useful internal utility, but does it need to be exposed like this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related note: the other geometry helpers are only exported from __init__ because of the off chance that someone was already importing any of them from toga.widgets.canvas, which used to be all one file. But we should probably deprecate and remove those too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be exposed as public API? It's definitely a useful internal utility, but does it need to be exposed like this?

I exposed it because it may be useful for backends which do implement the round rect in an HTML Canvas compatible way (which may only the web backend when it has its canvas class written) where the processing of the arguments is the main task. But yes, more generally I was a bit surprised that this was part of the Canvas API.

I'll remove the new items from the public API and fix the imports in the backends so that they import from ...canvas.geometry directly.

Copy link
Copy Markdown
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Thanks for those fixes - this looks great!

@freakboy3742 freakboy3742 merged commit c3729e0 into beeware:main Feb 5, 2026
57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants