зеркало из https://github.com/dotnet/winforms.git
Add tests for font measurement (#3538)
* Move WindowsFontQualityFromTextRenderingHint * Add some basic tests for font measurement * Remove WindowsFont.Size
This commit is contained in:
Родитель
5f4586df51
Коммит
632aa7e96c
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using static Interop;
|
||||
|
||||
namespace System.Windows.Forms
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using System.Windows.Forms.Internal;
|
||||
using static Interop;
|
||||
|
||||
|
@ -14,119 +15,93 @@ namespace System.Windows.Forms
|
|||
public static class TextRenderer
|
||||
{
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Point pt, Color foreColor)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
|
||||
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wg.DrawText(text, wf, pt, foreColor);
|
||||
}
|
||||
=> DrawTextInternal(dc, text, font, pt, foreColor);
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Point pt, Color foreColor, Color backColor)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
=> DrawTextInternal(dc, text, font, pt, foreColor, backColor);
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
public static void DrawText(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Point pt,
|
||||
Color foreColor,
|
||||
TextFormatFlags flags)
|
||||
=> DrawTextInternal(dc, text, font, pt, foreColor, flags: GetTextFormatFlags(flags));
|
||||
|
||||
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
|
||||
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wg.DrawText(text, wf, pt, foreColor, backColor);
|
||||
}
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Point pt, Color foreColor, TextFormatFlags flags)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var wgr = new WindowsGraphicsWrapper(dc, flags);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wgr.WindowsGraphics.DrawText(text, wf, pt, foreColor, GetTextFormatFlags(flags));
|
||||
}
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var wgr = new WindowsGraphicsWrapper(dc, flags);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wgr.WindowsGraphics.DrawText(text, wf, pt, foreColor, backColor, GetTextFormatFlags(flags));
|
||||
}
|
||||
public static void DrawText(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Point pt,
|
||||
Color foreColor,
|
||||
Color backColor,
|
||||
TextFormatFlags flags)
|
||||
=> DrawTextInternal(dc, text, font, pt, foreColor, backColor, flags: GetTextFormatFlags(flags));
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Rectangle bounds, Color foreColor)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
=> DrawTextInternal(dc, text, font, bounds, foreColor);
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
public static void DrawText(
|
||||
IDeviceContext dc,
|
||||
string? text, Font?
|
||||
font, Rectangle bounds,
|
||||
Color foreColor,
|
||||
Color backColor)
|
||||
=> DrawTextInternal(dc, text, font, bounds, foreColor, backColor);
|
||||
|
||||
public static void DrawText(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Rectangle bounds,
|
||||
Color foreColor,
|
||||
TextFormatFlags flags)
|
||||
=> DrawTextInternal(dc, text, font, bounds, foreColor, flags: GetTextFormatFlags(flags));
|
||||
|
||||
public static void DrawText(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Rectangle bounds,
|
||||
Color foreColor,
|
||||
Color backColor,
|
||||
TextFormatFlags flags)
|
||||
=> DrawTextInternal(dc, text, font, bounds, foreColor, backColor, flags: GetTextFormatFlags(flags));
|
||||
|
||||
private static void DrawTextInternal(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Point pt,
|
||||
Color foreColor,
|
||||
Color backColor = default,
|
||||
User32.DT flags = User32.DT.DEFAULT)
|
||||
=> DrawTextInternal(dc, text, font, new Rectangle(pt, WindowsGraphics.MaxSize), foreColor, backColor, flags);
|
||||
|
||||
private static void DrawTextInternal(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Rectangle bounds,
|
||||
Color foreColor,
|
||||
Color backColor = default,
|
||||
User32.DT flags = User32.DT.CENTER | User32.DT.VCENTER)
|
||||
{
|
||||
if (dc is null)
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
|
||||
// Avoid creating the HDC, etc if we're not going to do any drawing
|
||||
if (string.IsNullOrEmpty(text) || foreColor == Color.Transparent)
|
||||
return;
|
||||
|
||||
// This MUST come before retreiving the HDC, which locks the Graphics object
|
||||
Gdi32.QUALITY quality = FontQualityFromTextRenderingHint(dc);
|
||||
|
||||
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
|
||||
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wg.DrawText(text, wf, bounds, foreColor);
|
||||
}
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Rectangle bounds, Color foreColor, Color backColor)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
|
||||
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wg.DrawText(text, wf, bounds, foreColor, backColor);
|
||||
}
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Rectangle bounds, Color foreColor, TextFormatFlags flags)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var wgr = new WindowsGraphicsWrapper(dc, flags);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wgr.WindowsGraphics.DrawText(text, wf, bounds, foreColor, GetTextFormatFlags(flags));
|
||||
}
|
||||
|
||||
public static void DrawText(IDeviceContext dc, string? text, Font? font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var wgr = new WindowsGraphicsWrapper(dc, flags);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
wgr.WindowsGraphics.DrawText(text, wf, bounds, foreColor, backColor, GetTextFormatFlags(flags));
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, quality);
|
||||
wg.DrawText(text, wf, bounds, foreColor, backColor, flags);
|
||||
}
|
||||
|
||||
private static User32.DT GetTextFormatFlags(TextFormatFlags flags)
|
||||
|
@ -143,91 +118,59 @@ namespace System.Windows.Forms
|
|||
}
|
||||
|
||||
public static Size MeasureText(string? text, Font? font)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font);
|
||||
return WindowsGraphicsCacheManager.MeasurementGraphics.MeasureText(text, wf);
|
||||
}
|
||||
=> MeasureTextInternal(text, font, WindowsGraphics.MaxSize);
|
||||
|
||||
public static Size MeasureText(string? text, Font? font, Size proposedSize)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font);
|
||||
return WindowsGraphicsCacheManager.MeasurementGraphics.MeasureText(text, wf, proposedSize);
|
||||
}
|
||||
=> MeasureTextInternal(text, font, proposedSize);
|
||||
|
||||
public static Size MeasureText(string? text, Font? font, Size proposedSize, TextFormatFlags flags)
|
||||
=> MeasureTextInternal(text, font, proposedSize, flags);
|
||||
|
||||
public static Size MeasureText(IDeviceContext dc, string? text, Font? font)
|
||||
=> MeasureTextInternal(dc, text, font, WindowsGraphics.MaxSize);
|
||||
|
||||
public static Size MeasureText(IDeviceContext dc, string? text, Font? font, Size proposedSize)
|
||||
=> MeasureTextInternal(dc, text, font, proposedSize);
|
||||
|
||||
public static Size MeasureText(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Size proposedSize,
|
||||
TextFormatFlags flags)
|
||||
=> MeasureTextInternal(dc, text, font, proposedSize, flags);
|
||||
|
||||
private static Size MeasureTextInternal(
|
||||
string? text,
|
||||
Font? font,
|
||||
Size proposedSize,
|
||||
TextFormatFlags flags = TextFormatFlags.Bottom)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font);
|
||||
return WindowsGraphicsCacheManager.MeasurementGraphics.MeasureText(text, wf, proposedSize, GetTextFormatFlags(flags));
|
||||
}
|
||||
|
||||
public static Size MeasureText(IDeviceContext dc, string? text, Font? font)
|
||||
private static Size MeasureTextInternal(
|
||||
IDeviceContext dc,
|
||||
string? text,
|
||||
Font? font,
|
||||
Size proposedSize,
|
||||
TextFormatFlags flags = TextFormatFlags.Bottom)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
|
||||
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
return wg.MeasureText(text, wf);
|
||||
}
|
||||
|
||||
public static Size MeasureText(IDeviceContext dc, string? text, Font? font, Size proposedSize)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
|
||||
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
|
||||
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
|
||||
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
return wg.MeasureText(text, wf, proposedSize);
|
||||
}
|
||||
|
||||
public static Size MeasureText(IDeviceContext dc, string? text, Font? font, Size proposedSize, TextFormatFlags flags)
|
||||
{
|
||||
if (dc == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dc));
|
||||
}
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
|
||||
// This MUST come before retreiving the HDC, which locks the Graphics object
|
||||
Gdi32.QUALITY quality = FontQualityFromTextRenderingHint(dc);
|
||||
|
||||
using var wgr = new WindowsGraphicsWrapper(dc, flags);
|
||||
using var wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
|
||||
using var wf = WindowsGraphicsCacheManager.GetWindowsFont(font, quality);
|
||||
return wgr.WindowsGraphics.MeasureText(text, wf, proposedSize, GetTextFormatFlags(flags));
|
||||
}
|
||||
|
||||
|
@ -238,14 +181,39 @@ namespace System.Windows.Forms
|
|||
return SystemColors.GrayText;
|
||||
}
|
||||
|
||||
//Theme specs -- if the backcolor is darker than Control, we use
|
||||
// ControlPaint.Dark(backcolor). Otherwise we use ControlDark.
|
||||
Color disabledTextForeColor = SystemColors.ControlDark;
|
||||
if (ControlPaint.IsDarker(backColor, SystemColors.Control))
|
||||
// If the color is darker than SystemColors.Control make it slightly darker,
|
||||
// otherwise use the standard control dark color.
|
||||
|
||||
return ControlPaint.IsDarker(backColor, SystemColors.Control)
|
||||
? ControlPaint.Dark(backColor)
|
||||
: SystemColors.ControlDark;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to match the TextRenderingHint of the specified Graphics object with a LOGFONT.lfQuality value.
|
||||
/// </summary>
|
||||
private static Gdi32.QUALITY FontQualityFromTextRenderingHint(IDeviceContext? deviceContext)
|
||||
{
|
||||
if (!(deviceContext is Graphics g))
|
||||
{
|
||||
disabledTextForeColor = ControlPaint.Dark(backColor);
|
||||
return Gdi32.QUALITY.DEFAULT;
|
||||
}
|
||||
|
||||
switch (g.TextRenderingHint)
|
||||
{
|
||||
case TextRenderingHint.ClearTypeGridFit:
|
||||
return Gdi32.QUALITY.CLEARTYPE;
|
||||
case TextRenderingHint.AntiAliasGridFit:
|
||||
case TextRenderingHint.AntiAlias:
|
||||
return Gdi32.QUALITY.ANTIALIASED;
|
||||
case TextRenderingHint.SingleBitPerPixelGridFit:
|
||||
return Gdi32.QUALITY.PROOF;
|
||||
case TextRenderingHint.SingleBitPerPixel:
|
||||
return Gdi32.QUALITY.DRAFT;
|
||||
default:
|
||||
case TextRenderingHint.SystemDefault:
|
||||
return Gdi32.QUALITY.DEFAULT;
|
||||
}
|
||||
return disabledTextForeColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using System.Globalization;
|
||||
using static Interop;
|
||||
|
||||
|
@ -15,7 +14,6 @@ namespace System.Windows.Forms.Internal
|
|||
/// </summary>
|
||||
internal sealed partial class WindowsFont : ICloneable, IDisposable
|
||||
{
|
||||
private float _fontSize = -1.0f; // invalid value.
|
||||
private int _lineSpacing;
|
||||
private bool _ownHandle;
|
||||
private bool _ownedByCacheManager;
|
||||
|
@ -226,7 +224,7 @@ namespace System.Windows.Forms.Internal
|
|||
/// <summary>
|
||||
/// Gets the hash code for this WindowsFont.
|
||||
/// </summary>
|
||||
public override int GetHashCode() => HashCode.Combine(Style, CharSet, Size);
|
||||
public override int GetHashCode() => HashCode.Combine(Style, CharSet, LogFontHeight);
|
||||
|
||||
/// <summary>
|
||||
/// Clones this object.
|
||||
|
@ -238,7 +236,10 @@ namespace System.Windows.Forms.Internal
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "[{0}: Name={1}, Size={2} points, Height={3} pixels, Sytle={4}]", GetType().Name, _logFont.FaceName.ToString(), Size, Height, Style);
|
||||
return string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
"[{0}: Name={1}, lfHeight={2}, Height={3} pixels, Sytle={4}]",
|
||||
GetType().Name, _logFont.FaceName.ToString(), LogFontHeight, Height, Style);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
@ -338,63 +339,5 @@ namespace System.Windows.Forms.Internal
|
|||
/// The font's face name.
|
||||
/// </summary>
|
||||
public string Name => _logFont.FaceName.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the character height (as opposed to the cell height) of the font represented by this object in points.
|
||||
/// Consider
|
||||
/// </summary>
|
||||
public float Size
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fontSize < 0.0f)
|
||||
{
|
||||
WindowsGraphics wg = WindowsGraphicsCacheManager.MeasurementGraphics;
|
||||
|
||||
// No need to reset the font (if changed) since we always set the font before using the MeasurementGraphics
|
||||
// in WindowsGraphics methods.
|
||||
wg.DeviceContext.SelectFont(this);
|
||||
|
||||
Gdi32.TEXTMETRICW tm = wg.GetTextMetrics();
|
||||
|
||||
// Convert the font character height to points. If lfHeight is negative, Windows
|
||||
// treats the absolute value of that number as a desired font height compatible with
|
||||
// the point size; in this case lfHeight will roughly match the tmHeight field of
|
||||
// the TEXTMETRIC structure less the tmInternalLeading field.
|
||||
int height = _logFont.lfHeight > 0 ? tm.tmHeight : (tm.tmHeight - tm.tmInternalLeading);
|
||||
|
||||
_fontSize = height * 72f / wg.DeviceContext.DpiY;
|
||||
}
|
||||
|
||||
return _fontSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to match the TextRenderingHint of the specified Graphics object with a LOGFONT.lfQuality value.
|
||||
/// </summary>
|
||||
public static Gdi32.QUALITY WindowsFontQualityFromTextRenderingHint(Graphics? g)
|
||||
{
|
||||
if (g == null)
|
||||
{
|
||||
return Gdi32.QUALITY.DEFAULT;
|
||||
}
|
||||
|
||||
switch (g.TextRenderingHint)
|
||||
{
|
||||
case TextRenderingHint.ClearTypeGridFit:
|
||||
return Gdi32.QUALITY.CLEARTYPE;
|
||||
case TextRenderingHint.AntiAliasGridFit:
|
||||
case TextRenderingHint.AntiAlias:
|
||||
return Gdi32.QUALITY.ANTIALIASED;
|
||||
case TextRenderingHint.SingleBitPerPixelGridFit:
|
||||
return Gdi32.QUALITY.PROOF;
|
||||
case TextRenderingHint.SingleBitPerPixel:
|
||||
return Gdi32.QUALITY.DRAFT;
|
||||
default:
|
||||
case TextRenderingHint.SystemDefault:
|
||||
return Gdi32.QUALITY.DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,46 +71,6 @@ namespace System.Windows.Forms.Internal
|
|||
public void DrawAndFillEllipse(WindowsPen pen, WindowsBrush brush, Rectangle bounds)
|
||||
=> DrawEllipse(pen, brush, bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text at the specified point, using the given Font and foreColor.
|
||||
/// CR/LF are honored.
|
||||
/// </summary>
|
||||
public void DrawText(string? text, WindowsFont? font, Point pt, Color foreColor)
|
||||
=> DrawText(text, font, pt, foreColor, Color.Empty, User32.DT.DEFAULT);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text at the specified point, using the given Font, foreColor and backColor.
|
||||
/// CR/LF are honored.
|
||||
/// </summary>
|
||||
public void DrawText(string? text, WindowsFont? font, Point pt, Color foreColor, Color backColor)
|
||||
=> DrawText(text, font, pt, foreColor, backColor, User32.DT.DEFAULT);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text at the specified point, using the given Font and foreColor, and according to the
|
||||
/// specified flags.
|
||||
/// </summary>
|
||||
public void DrawText(string? text, WindowsFont? font, Point pt, Color foreColor, User32.DT flags)
|
||||
=> DrawText(text, font, pt, foreColor, Color.Empty, flags);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text at the specified point, using the given Font, foreColor and backColor, and according
|
||||
/// to the specified flags.
|
||||
/// </summary>
|
||||
public void DrawText(string? text, WindowsFont? font, Point pt, Color foreColor, Color backColor, User32.DT flags)
|
||||
=> DrawText(text, font, new Rectangle(pt, MaxSize), foreColor, backColor, flags);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text centered in the given rectangle and using the given Font and foreColor.
|
||||
/// </summary>
|
||||
public void DrawText(string? text, WindowsFont? font, Rectangle bounds, Color foreColor)
|
||||
=> DrawText(text, font, bounds, foreColor, Color.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text centered in the given rectangle and using the given Font, foreColor and backColor.
|
||||
/// </summary>
|
||||
public void DrawText(string? text, WindowsFont? font, Rectangle bounds, Color foreColor, Color backColor)
|
||||
=> DrawText(text, font, bounds, foreColor, backColor, User32.DT.CENTER | User32.DT.VCENTER);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text in the given bounds, using the given Font and foreColor, and according to the specified flags.
|
||||
/// </summary>
|
||||
|
@ -283,21 +243,6 @@ namespace System.Windows.Forms.Internal
|
|||
return new Size(size.Width, size.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Size in logical units of the given text using the given Font.
|
||||
/// CR/LF/TAB are taken into account.
|
||||
/// </summary>
|
||||
public Size MeasureText(string? text, WindowsFont? font)
|
||||
=> MeasureText(text, font, MaxSize, User32.DT.BOTTOM);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Size in logical units of the given text using the given Font and using the specified rectangle
|
||||
/// as the text bounding box (see overload below for more info).
|
||||
/// TAB/CR/LF are taken into account.
|
||||
/// </summary>
|
||||
public Size MeasureText(string? text, WindowsFont? font, Size proposedSize)
|
||||
=> MeasureText(text, font, proposedSize, User32.DT.BOTTOM);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Size in logical units of the given text using the given Font, and according to the formatting flags.
|
||||
/// The proposed size is used to create a bounding rectangle as follows:
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms.Internal;
|
||||
using Xunit;
|
||||
using static Interop;
|
||||
|
||||
namespace System.Windows.Forms.Tests.Text
|
||||
{
|
||||
public class FontMetrics
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Arial", 9.0f, 15)]
|
||||
[InlineData("Arial", 12.0f, 18)]
|
||||
[InlineData("Microsoft Sans Serif", 16.0f, 26)]
|
||||
[InlineData("Times New Roman", 11.0f, 17)]
|
||||
[InlineData("MS Gothic", 10.0f, 14)]
|
||||
public void Font_GetHeight(string family, float size, int height)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
Assert.Equal(height, windowsFont.Height);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Arial", 9.0f, 1 /* DEFAULT_CHARSET */)]
|
||||
[InlineData("Arial", 12.0f, 1)]
|
||||
[InlineData("Microsoft Sans Serif", 16.0f, 1)]
|
||||
[InlineData("Times New Roman", 11.0f, 1)]
|
||||
[InlineData("MS Gothic", 11.0f, 1)]
|
||||
public void Font_GetCharSet(string family, float size, byte charset)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
Assert.Equal(charset, windowsFont.CharSet);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Arial", 9.0f, 2.5f)]
|
||||
[InlineData("Arial", 12.0f, 3.0f)]
|
||||
[InlineData("Microsoft Sans Serif", 16.0f, 4.3333335f)]
|
||||
[InlineData("Times New Roman", 11.0f, 2.8333333f)]
|
||||
[InlineData("MS Gothic", 10.0f, 2.3333333f)]
|
||||
public void Font_GetOverhangPadding(string family, float size, float expected)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
WindowsGraphics graphics = WindowsGraphicsCacheManager.MeasurementGraphics;
|
||||
Assert.Equal(expected, graphics.GetOverhangPadding(windowsFont));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Arial", 9.0f, 3, 4)]
|
||||
[InlineData("Arial", 12.0f, 3, 5)]
|
||||
[InlineData("Microsoft Sans Serif", 16.0f, 5, 7)]
|
||||
[InlineData("Times New Roman", 11.0f, 3, 5)]
|
||||
[InlineData("MS Gothic", 10.0f, 3, 4)]
|
||||
public void Font_GetTextMargins(string family, float size, int left, int right)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
WindowsGraphics graphics = WindowsGraphicsCacheManager.MeasurementGraphics;
|
||||
User32.DRAWTEXTPARAMS margins = graphics.GetTextMargins(windowsFont);
|
||||
Assert.Equal(left, margins.iLeftMargin);
|
||||
Assert.Equal(right, margins.iRightMargin);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Arial", 9.0f, 73, 15)]
|
||||
[InlineData("Arial", 12.0f, 95, 18)]
|
||||
[InlineData("Microsoft Sans Serif", 16.0f, 136, 26)]
|
||||
[InlineData("Times New Roman", 11.0f, 84, 17)]
|
||||
[InlineData("MS Gothic", 10.0f, 91, 14)]
|
||||
public void Font_GetTextExtent(string family, float size, int width, int height)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
WindowsGraphics graphics = WindowsGraphicsCacheManager.MeasurementGraphics;
|
||||
Size extent = graphics.GetTextExtent("Whizzo Butter", windowsFont);
|
||||
Assert.Equal(width, extent.Width);
|
||||
Assert.Equal(height, extent.Height);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MeasureTextData))]
|
||||
public void Font_MeasureText(string family, float size, Size proposedSize, uint dt, Size expected)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
WindowsGraphics graphics = WindowsGraphicsCacheManager.MeasurementGraphics;
|
||||
Size measure = graphics.MeasureText("Windows Foundation Classes", windowsFont, proposedSize, (User32.DT)dt);
|
||||
Assert.Equal(expected, measure);
|
||||
}
|
||||
|
||||
public static TheoryData<string, float, Size, uint, Size> MeasureTextData =>
|
||||
new TheoryData<string, float, Size, uint, Size>
|
||||
{
|
||||
{ "Arial", 9.0f, new Size(-1, -1), (uint)User32.DT.BOTTOM, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(-1, -1), (uint)User32.DT.BOTTOM, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(-1, -1), (uint)User32.DT.BOTTOM, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(-1, -1), (uint)User32.DT.BOTTOM, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(-1, -1), (uint)User32.DT.BOTTOM, new Size(189, 14) },
|
||||
{ "Arial", 9.0f, new Size(0, 0), (uint)User32.DT.BOTTOM, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(0, 0), (uint)User32.DT.BOTTOM, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(0, 0), (uint)User32.DT.BOTTOM, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(0, 0), (uint)User32.DT.BOTTOM, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(0, 0), (uint)User32.DT.BOTTOM, new Size(189, 14) },
|
||||
{ "Arial", 9.0f, new Size(1, 1), (uint)User32.DT.BOTTOM, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(1, 1), (uint)User32.DT.BOTTOM, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(1, 1), (uint)User32.DT.BOTTOM, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(1, 1), (uint)User32.DT.BOTTOM, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(1, 1), (uint)User32.DT.BOTTOM, new Size(189, 14) },
|
||||
{ "Arial", 9.0f, new Size(300, 300), (uint)User32.DT.BOTTOM, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(300, 300), (uint)User32.DT.BOTTOM, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(300, 300), (uint)User32.DT.BOTTOM, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(300, 300), (uint)User32.DT.BOTTOM, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(300, 300), (uint)User32.DT.BOTTOM, new Size(189, 14) },
|
||||
{ "Arial", 9.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.BOTTOM, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.BOTTOM, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.BOTTOM, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.BOTTOM, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.BOTTOM, new Size(189, 14) },
|
||||
{ "Arial", 9.0f, new Size(1, 1), (uint)User32.DT.SINGLELINE, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(1, 1), (uint)User32.DT.SINGLELINE, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(1, 1), (uint)User32.DT.SINGLELINE, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(1, 1), (uint)User32.DT.SINGLELINE, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(1, 1), (uint)User32.DT.SINGLELINE, new Size(189, 14) },
|
||||
{ "Arial", 9.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.SINGLELINE, new Size(173, 15) },
|
||||
{ "Arial", 12.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.SINGLELINE, new Size(215, 18) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.SINGLELINE, new Size(299, 26) },
|
||||
{ "Times New Roman", 11.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.SINGLELINE, new Size(179, 17) },
|
||||
{ "MS Gothic", 10.0f, new Size(int.MaxValue, int.MaxValue), (uint)User32.DT.SINGLELINE, new Size(189, 14) },
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(AdjustData))]
|
||||
public void Font_AdjustForVerticalAlignment(string family, float size, Rectangle bounds, uint dt, Rectangle expected)
|
||||
{
|
||||
using Font font = new Font(family, size);
|
||||
if (font.Name != family)
|
||||
{
|
||||
// Not installed on this machine
|
||||
return;
|
||||
}
|
||||
|
||||
using WindowsFont windowsFont = WindowsFont.FromFont(font, Gdi32.QUALITY.CLEARTYPE);
|
||||
WindowsGraphics graphics = WindowsGraphicsCacheManager.MeasurementGraphics;
|
||||
graphics.DeviceContext.SelectFont(windowsFont);
|
||||
User32.DRAWTEXTPARAMS param = default;
|
||||
Rectangle result = WindowsGraphics.AdjustForVerticalAlignment(
|
||||
graphics,
|
||||
"Windows Foundation Classes",
|
||||
bounds,
|
||||
(User32.DT)dt,
|
||||
ref param);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
public static TheoryData<string, float, Rectangle, uint, Rectangle> AdjustData =>
|
||||
new TheoryData<string, float, Rectangle, uint, Rectangle>
|
||||
{
|
||||
{ "Arial", 9.0f, new Rectangle(1, 1, 1, 1), (uint)User32.DT.BOTTOM, new Rectangle(1, 1, 1, 1) },
|
||||
{ "Arial", 12.0f, new Rectangle(1, 1, 1, 1), (uint)User32.DT.BOTTOM, new Rectangle(1, 1, 1, 1) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Rectangle(1, 1, 1, 1), (uint)User32.DT.BOTTOM, new Rectangle(1, 1, 1, 1) },
|
||||
{ "Times New Roman", 11.0f, new Rectangle(1, 1, 1, 1), (uint)User32.DT.BOTTOM, new Rectangle(1, 1, 1, 1) },
|
||||
{ "MS Gothic", 10.0f, new Rectangle(1, 1, 1, 1), (uint)User32.DT.BOTTOM, new Rectangle(1, 1, 1, 1) },
|
||||
{ "Arial", 9.0f, new Rectangle(1, 1, 100, 100), (uint)User32.DT.BOTTOM, new Rectangle(1, 86, 100, 100) },
|
||||
{ "Arial", 12.0f, new Rectangle(1, 1, 100, 100), (uint)User32.DT.BOTTOM, new Rectangle(1, 83, 100, 100) },
|
||||
{ "Microsoft Sans Serif", 16.0f, new Rectangle(1, 1, 100, 100), (uint)User32.DT.BOTTOM, new Rectangle(1, 75, 100, 100) },
|
||||
{ "Times New Roman", 11.0f, new Rectangle(1, 1, 100, 100), (uint)User32.DT.BOTTOM, new Rectangle(1, 84, 100, 100) },
|
||||
{ "MS Gothic", 10.0f, new Rectangle(1, 1, 100, 100), (uint)User32.DT.BOTTOM, new Rectangle(1, 87, 100, 100) },
|
||||
};
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче