API Proposal: Add safe overloads to TextRenderer to get output strings.
- Dominant language
- C#
- Stars
- 4.9k
- Forks
- 1.1k
- Avg merge
- 1d 13m
- Merged PRs (30d)
- 85
Description
## Proposal
We need to add new overloads that allow getting out the actual rendered string when using ellipses options (`TextFormatFlags.PathEllipsis` and `TextFormatFlags.WordEllipsis`). This is currently done with `TextFormatFlags.ModifyString`, which mutates the input `string`. We block this option in the newer span overloads and have obsoleted it.
This is a follow-up to #3651.
``` C#
namespace System.Windows.Forms
{
public sealed class TextRenderer
{
// Existing flags APIs:
public static void DrawText(IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags);
public static Size MeasureText(IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags);
public static Size MeasureText(string text, Font font, Size proposedSize, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, ReadOnlySpan text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, ReadOnlySpan text, Font font, Point pt, Color foreColor, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, ReadOnlySpan text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags);
public static void DrawText(IDeviceContext dc, ReadOnlySpan text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags);
public static Size MeasureText(IDeviceContext dc, ReadOnlySpan text, Font font, Size proposedSize, TextFormatFlags flags);
public static Size MeasureText(ReadOnlySpan text, Font font, Size proposedSize, TextFormatFlags flags);
// Proposed
public static void DrawText(IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, out string outputText);
public static void DrawText(IDeviceContext dc, ReadOnlySpan text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, Span outputTextBuffer, out int outputTextLength);
public static void DrawText(IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, out string outputText);
public static void DrawText(IDeviceContext dc, ReadOnlySpan text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, Span outputTextBuffer, out int outputTextLength);
public static Size MeasureText(IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, out string outputText);
public static Size MeasureText(IDeviceContext dc, ReadOnlySpan text, Font font, Size proposedSize, TextFormatFlags flags, Span outputTextBuffer, out int outputTextLength);
public static Size MeasureText(string text, Font font, Size proposedSize, TextFormatFlags flags, out string outputText);
public static Size MeasureText(ReadOnlySpan text, Font font, Size proposedSize, TextFormatFlags flags, Span outputTextBuffer, out int outputTextLength);
}
}
```
## Justification
It is still a valid scenario to want to know what Windows actually outputs. Providing these overloads will let us fully block the mutation of the input strings, which is extremely dangerous.
The proposed surface area aligns with the existing API definitions and allows utilizing the same buffer for the Span APIs for advanced users.
## Implementation Details
These APIs will presume you want the output string _without_ requiring the obsoleted flag. When the ellipses flags are set we will get the actual output string from Windows and either create a new string or copy the output into the `Span` buffer provided and return the length. In all other scenarios we will pass back the input.
The `Span` overloads will require that the passed in `Span` is at least as long as the input `ReadOnlySpan`. If it is not, the API will throw.
We'll skip the overloads for just `foreColor` and document that `Color.Empty` is required for a transparent background as these APIs are not as common.
We'll match additional throwing behavior of the original APIs. The original APIs did not throw for null or empty strings, they just no-op.
Contributor guide
Assessment
This issue has not been assessed yet.