dotnet/winforms

API Proposal: Add safe overloads to TextRenderer to get output strings.

Open

#3710 aperta il 10 ago 2020

Vedi su GitHub
 (4 commenti) (2 reazioni) (2 assegnatari)C# (922 fork)batch import
api-approvedhelp wanted

Metriche repository

Star
 (4100 star)
Metriche merge PR
 (Merge medio 14g 22h) (56 PR mergiate in 30 g)

Descrizione

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.

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<char> text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags);
        public static void DrawText(IDeviceContext dc, ReadOnlySpan<char> text, Font font, Point pt, Color foreColor, TextFormatFlags flags);
        public static void DrawText(IDeviceContext dc, ReadOnlySpan<char> text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags);
        public static void DrawText(IDeviceContext dc, ReadOnlySpan<char> text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags);
        public static Size MeasureText(IDeviceContext dc, ReadOnlySpan<char> text, Font font, Size proposedSize, TextFormatFlags flags);
        public static Size MeasureText(ReadOnlySpan<char> 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<char> text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, Span<char> 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<char> text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, Span<char> 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<char> text, Font font, Size proposedSize, TextFormatFlags flags, Span<char> outputTextBuffer, out int outputTextLength);
        public static Size MeasureText(string text, Font font, Size proposedSize, TextFormatFlags flags, out string outputText);
        public static Size MeasureText(ReadOnlySpan<char> text, Font font, Size proposedSize, TextFormatFlags flags, Span<char> 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<char> is at least as long as the input ReadOnlySpan<char>. 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.

Guida contributor