| File: System\Drawing\SystemFonts.cs | Web Access |
| Project: src\winforms\src\System.Drawing.Common\src\System.Drawing.Common.csproj (System.Drawing.Common) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing.Interop; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.Drawing; public static class SystemFonts { public static Font? GetFontByName(string systemFontName) { if (nameof(CaptionFont).Equals(systemFontName)) { return CaptionFont; } else if (nameof(DefaultFont).Equals(systemFontName)) { return DefaultFont; } else if (nameof(DialogFont).Equals(systemFontName)) { return DialogFont; } else if (nameof(IconTitleFont).Equals(systemFontName)) { return IconTitleFont; } else if (nameof(MenuFont).Equals(systemFontName)) { return MenuFont; } else if (nameof(MessageBoxFont).Equals(systemFontName)) { return MessageBoxFont; } else if (nameof(SmallCaptionFont).Equals(systemFontName)) { return SmallCaptionFont; } else if (nameof(StatusFont).Equals(systemFontName)) { return StatusFont; } return null; } private static unsafe bool GetNonClientMetrics(out NONCLIENTMETRICSW metrics) { metrics = new NONCLIENTMETRICSW { cbSize = (uint)sizeof(NONCLIENTMETRICSW) }; return PInvokeCore.SystemParametersInfo(ref metrics); } public static Font? CaptionFont { get { Font? captionFont = null; if (GetNonClientMetrics(out NONCLIENTMETRICSW metrics)) { captionFont = GetFontFromData(in metrics.lfCaptionFont); captionFont.SetSystemFontName(nameof(CaptionFont)); } return captionFont; } } public static Font? SmallCaptionFont { get { Font? smcaptionFont = null; if (GetNonClientMetrics(out NONCLIENTMETRICSW metrics)) { smcaptionFont = GetFontFromData(in metrics.lfSmCaptionFont); smcaptionFont.SetSystemFontName(nameof(SmallCaptionFont)); } return smcaptionFont; } } public static Font? MenuFont { get { Font? menuFont = null; if (GetNonClientMetrics(out NONCLIENTMETRICSW metrics)) { menuFont = GetFontFromData(metrics.lfMenuFont); menuFont.SetSystemFontName(nameof(MenuFont)); } return menuFont; } } public static Font? StatusFont { get { Font? statusFont = null; if (GetNonClientMetrics(out NONCLIENTMETRICSW metrics)) { statusFont = GetFontFromData(metrics.lfStatusFont); statusFont.SetSystemFontName(nameof(StatusFont)); } return statusFont; } } public static Font? MessageBoxFont { get { Font? messageBoxFont = null; if (GetNonClientMetrics(out NONCLIENTMETRICSW metrics)) { messageBoxFont = GetFontFromData(metrics.lfMessageFont); messageBoxFont.SetSystemFontName(nameof(MessageBoxFont)); } return messageBoxFont; } } private static bool IsCriticalFontException(Exception ex) => // In any of these cases we'll handle the exception. ex is not (ExternalException or ArgumentException // GDI+ throws this one for many reasons other than actual OOM. or OutOfMemoryException or InvalidOperationException or NotImplementedException or FileNotFoundException); public static unsafe Font? IconTitleFont { get { Font? iconTitleFont = null; LOGFONT itfont = default; if (PInvokeCore.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETICONTITLELOGFONT, (uint)sizeof(LOGFONT), &itfont, 0)) { iconTitleFont = GetFontFromData(in itfont); iconTitleFont.SetSystemFontName(nameof(IconTitleFont)); } return iconTitleFont; } } public static Font DefaultFont { get { Font? defaultFont = null; // For Arabic systems, always return Tahoma 8. if (PInvokeCore.GetSystemDefaultLCID() == PInvoke.LANG_ARABIC) { try { defaultFont = new Font("Tahoma", 8); } catch (Exception ex) when (!IsCriticalFontException(ex)) { } } // First try DEFAULT_GUI. if (defaultFont is null) { HFONT handle = (HFONT)PInvokeCore.GetStockObject(GET_STOCK_OBJECT_FLAGS.DEFAULT_GUI_FONT); try { using Font fontInWorldUnits = Font.FromHfont(handle); defaultFont = FontInPoints(fontInWorldUnits); } catch (ArgumentException) { // This can happen in theory if we end up pulling a non-TrueType font } } // If DEFAULT_GUI didn't work, try Tahoma. if (defaultFont is null) { try { defaultFont = new Font("Tahoma", 8); } catch (ArgumentException) { } } // Use GenericSansSerif as a last resort - this will always work. defaultFont ??= new Font(FontFamily.GenericSansSerif, 8); if (defaultFont.Unit != GraphicsUnit.Point) { defaultFont = FontInPoints(defaultFont); } Debug.Assert(defaultFont is not null, "defaultFont wasn't set."); defaultFont.SetSystemFontName(nameof(DefaultFont)); return defaultFont; } } public static Font DialogFont { get { Font? dialogFont = null; if (PInvokeCore.GetSystemDefaultLCID() == PInvoke.LANG_JAPANESE) { // Always return DefaultFont for Japanese cultures. dialogFont = DefaultFont; } else { try { // Use MS Shell Dlg 2, 8pt for anything other than Japanese. dialogFont = new Font("MS Shell Dlg 2", 8); } catch (ArgumentException) { // This can happen in theory if we end up pulling a non-TrueType font } } if (dialogFont is null) { dialogFont = DefaultFont; } else if (dialogFont.Unit != GraphicsUnit.Point) { dialogFont = FontInPoints(dialogFont); } // For Japanese cultures, SystemFonts.DefaultFont returns a new Font object every time it is invoked. // So for Japanese we return the DefaultFont with its SystemFontName set to DialogFont. dialogFont!.SetSystemFontName(nameof(DialogFont)); return dialogFont; } } private static Font FontInPoints(Font font) { return new Font(font.FontFamily, font.SizeInPoints, font.Style, GraphicsUnit.Point, font.GdiCharSet, font.GdiVerticalFont); } private static Font GetFontFromData(in LOGFONTW logFont) => GetFontFromData(Unsafe.As<LOGFONTW, LOGFONT>(ref Unsafe.AsRef(in logFont))); private static Font GetFontFromData(in LOGFONT logFont) { Font? font = null; try { font = Font.FromLogFont(in logFont); } catch (Exception ex) when (!IsCriticalFontException(ex)) { } return font is null ? DefaultFont : font.Unit != GraphicsUnit.Point ? FontInPoints(font) : font; } }