diff --git a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs
index f58c6bdfc32..76a26022c6c 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs
@@ -730,9 +730,41 @@ public void DrawRoundedRectangle(Pen pen, Rectangle rect, Size radius) =>
/// The radius width and height used to round the corners of the rectangle.
public void DrawRoundedRectangle(Pen pen, RectangleF rect, SizeF radius)
{
+ ArgumentNullException.ThrowIfNull(pen);
+
+ // Inset the stroke by half the pen width so the entire border sits inside the requested
+ // bounds on a consistent sub-pixel grid. Combined with high-quality pixel offset and
+ // anti-aliasing this realigns the corner arcs with the straight edges and removes the
+ // artifacts a centered, default-offset stroke would otherwise produce.
+ RectangleF strokeRect = rect;
+ SizeF strokeRadius = radius;
+
+ if (rect.Width > pen.Width && rect.Height > pen.Width)
+ {
+ float inset = pen.Width / 2f;
+ strokeRect = RectangleF.Inflate(rect, -inset, -inset);
+ strokeRadius = new(
+ Math.Max(0f, radius.Width - inset),
+ Math.Max(0f, radius.Height - inset));
+ }
+
using GraphicsPath path = new();
- path.AddRoundedRectangle(rect, radius);
- DrawPath(pen, path);
+ path.AddRoundedRectangle(strokeRect, strokeRadius);
+
+ Drawing2D.SmoothingMode previousSmoothingMode = this.SmoothingMode;
+ PixelOffsetMode previousPixelOffsetMode = this.PixelOffsetMode;
+
+ try
+ {
+ this.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias;
+ this.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ DrawPath(pen, path);
+ }
+ finally
+ {
+ this.SmoothingMode = previousSmoothingMode;
+ this.PixelOffsetMode = previousPixelOffsetMode;
+ }
}
#endif
@@ -1204,9 +1236,28 @@ public void FillRoundedRectangle(Brush brush, Rectangle rect, Size radius) =>
/// The radius width and height used to round the corners of the rectangle.
public void FillRoundedRectangle(Brush brush, RectangleF rect, SizeF radius)
{
+ ArgumentNullException.ThrowIfNull(brush);
+
using GraphicsPath path = new();
path.AddRoundedRectangle(rect, radius);
- FillPath(brush, path);
+
+ // Anti-aliasing plus high-quality pixel offset gives the filled corners the same crisp,
+ // uniform edge as the straight sides instead of the softer, offset arcs the default
+ // rendering mode produces.
+ Drawing2D.SmoothingMode previousSmoothingMode = this.SmoothingMode;
+ PixelOffsetMode previousPixelOffsetMode = this.PixelOffsetMode;
+
+ try
+ {
+ this.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias;
+ this.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ FillPath(brush, path);
+ }
+ finally
+ {
+ this.SmoothingMode = previousSmoothingMode;
+ this.PixelOffsetMode = previousPixelOffsetMode;
+ }
}
#endif
diff --git a/src/System.Drawing.Common/tests/System/Drawing/GraphicsTests.cs b/src/System.Drawing.Common/tests/System/Drawing/GraphicsTests.cs
index e921aedb521..ed39da837fc 100644
--- a/src/System.Drawing.Common/tests/System/Drawing/GraphicsTests.cs
+++ b/src/System.Drawing.Common/tests/System/Drawing/GraphicsTests.cs
@@ -3002,5 +3002,44 @@ public void Graphics_FillRoundedRectangle_Float()
graphics.FillRoundedRectangle(Brushes.Green, new RectangleF(0, 0, 10, 10), new(2, 2));
VerifyBitmapNotEmpty(bitmap);
}
+
+ [Fact]
+ public void Graphics_DrawRoundedRectangle_ThickPen()
+ {
+ using Bitmap bitmap = new(20, 20);
+ using Graphics graphics = Graphics.FromImage(bitmap);
+ using Pen pen = new(Color.Blue, 3);
+ graphics.DrawRoundedRectangle(pen, new RectangleF(0, 0, 20, 20), new(6, 6));
+ VerifyBitmapNotEmpty(bitmap);
+ }
+
+ [Fact]
+ public void Graphics_DrawRoundedRectangle_RestoresRenderingModes()
+ {
+ using Bitmap bitmap = new(20, 20);
+ using Graphics graphics = Graphics.FromImage(bitmap);
+ graphics.SmoothingMode = SmoothingMode.None;
+ graphics.PixelOffsetMode = PixelOffsetMode.Half;
+
+ using Pen pen = new(Color.Blue, 3);
+ graphics.DrawRoundedRectangle(pen, new RectangleF(0, 0, 20, 20), new(6, 6));
+
+ graphics.SmoothingMode.Should().Be(SmoothingMode.None);
+ graphics.PixelOffsetMode.Should().Be(PixelOffsetMode.Half);
+ }
+
+ [Fact]
+ public void Graphics_FillRoundedRectangle_RestoresRenderingModes()
+ {
+ using Bitmap bitmap = new(20, 20);
+ using Graphics graphics = Graphics.FromImage(bitmap);
+ graphics.SmoothingMode = SmoothingMode.None;
+ graphics.PixelOffsetMode = PixelOffsetMode.Half;
+
+ graphics.FillRoundedRectangle(Brushes.Green, new RectangleF(0, 0, 20, 20), new(6, 6));
+
+ graphics.SmoothingMode.Should().Be(SmoothingMode.None);
+ graphics.PixelOffsetMode.Should().Be(PixelOffsetMode.Half);
+ }
#endif
}