New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Add ReadOnlySpan<char> overloads to System.Drawing.Graphics #8844
Comments
Tagging subscribers to this area: @dotnet/area-system-drawing Issue DetailsBackground and motivationWhen drawing strings manually in WinForms, new text is frequently created. It would be better to add an overload that accepts API Proposalnamespace System.Drawing
{
public sealed partial class Graphics : System.MarshalByRefObject, System.Drawing.IDeviceContext, System.IDisposable
{
// Existing:
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat? format) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat? format) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat? format) { }
public System.Drawing.Region[] MeasureCharacterRanges(string? text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat, out int charactersFitted, out int linesFilled) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, int width) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, int width, System.Drawing.StringFormat? format) { throw null; }
// Proposal
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat? format) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat? format) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat? format) { }
public System.Drawing.Region[] MeasureCharacterRanges(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat, out int charactersFitted, out int linesFilled) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, int width) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, int width, System.Drawing.StringFormat? format) { throw null; }
}
public sealed partial class GraphicsPath : System.MarshalByRefObject, System.ICloneable, System.IDisposable
{
// Existing:
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Point origin, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.PointF origin, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Rectangle layoutRect, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? format) { }
// Proposal
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Point origin, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.PointF origin, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Rectangle layoutRect, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? format) { }
}
} API UsageIt is possible to pass buffers on the stack. GraphicsPath gp = new GraphicsPath();
...
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
Span<char> buf = stackalloc char[512];
DateTime.Now.TryFormat(buf, out var writtern);
g.DrawString(buf, ...);
gp.AddString(buf, ...);
} Alternative DesignsI can't think of any. RisksI can't think of any.
|
Note: |
cc @JeremyKuhne |
Seems rational. Would just need to double check that the underlying GDI+ APIs all take a length (and not a null-terminated string). I believe that is the case... |
@JeremyKuhne is this something that WinForms would benefit from? We try to not churn up System.Drawing.Common much. |
WinForms customers would, and the implementation should be trivial. |
Got it. Who would be the champion to drive this forward and represent it in the API Review meeting? Would it be someone on your team, you or us? // Just making sure that I understand the process for these Drawing issues. |
Assuming that all the underlying APIs take a (w)char and separate length (vs expecting null termination), looks good as proposed. namespace System.Drawing
{
public sealed partial class Graphics : System.MarshalByRefObject, System.Drawing.IDeviceContext, System.IDisposable
{
// Existing:
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat? format) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat? format) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y) { }
public void DrawString(string? s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat? format) { }
public System.Drawing.Region[] MeasureCharacterRanges(string? text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat, out int charactersFitted, out int linesFilled) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, int width) { throw null; }
public System.Drawing.SizeF MeasureString(string? text, System.Drawing.Font font, int width, System.Drawing.StringFormat? format) { throw null; }
// Proposal
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat? format) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat? format) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y) { }
public void DrawString(ReadOnlySpan<char> s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat? format) { }
public System.Drawing.Region[] MeasureCharacterRanges(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.PointF origin, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, System.Drawing.SizeF layoutArea, System.Drawing.StringFormat? stringFormat, out int charactersFitted, out int linesFilled) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, int width) { throw null; }
public System.Drawing.SizeF MeasureString(ReadOnlySpan<char> text, System.Drawing.Font font, int width, System.Drawing.StringFormat? format) { throw null; }
}
public sealed partial class GraphicsPath : System.MarshalByRefObject, System.ICloneable, System.IDisposable
{
// Existing:
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Point origin, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.PointF origin, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Rectangle layoutRect, System.Drawing.StringFormat? format) { }
public void AddString(string s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? format) { }
// Proposal
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Point origin, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.PointF origin, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.Rectangle layoutRect, System.Drawing.StringFormat? format) { }
public void AddString(ReadOnlySpan<char> s, System.Drawing.FontFamily family, int style, float emSize, System.Drawing.RectangleF layoutRect, System.Drawing.StringFormat? format) { }
}
} |
Adds `ReadOnlySpan<char>` overloads to `Graphics.DrawString`, `MeasureCharacterRanges`, and `MeasureString`. Cleaned up docs for these methods as well and called span/string overloads in existing tests. Fixes: dotnet#8844
Adds `ReadOnlySpan<char>` overloads to `Graphics.DrawString`, `MeasureCharacterRanges`, and `MeasureString`. Cleaned up docs for these methods as well and called span/string overloads in existing tests. Fixes: #8844
Background and motivation
When drawing strings manually in WinForms, new text is frequently created.
Since the methods
System.Drawing.Graphics
andSystem.Drawing.GraphicsPath
only accept stringsString allocations occur frequently.
It would be better to add an overload that accepts
ReadOnlySpan<char>
so that the buffer can be passed directly.API Proposal
API Usage
It is possible to pass buffers on the stack.
Alternative Designs
I can't think of any.
Risks
I can't think of any.
The text was updated successfully, but these errors were encountered: