FontFamily
Defines a group of type faces having a similar basic design and certain variations in styles. This class cannot be inherited.
using System.Diagnostics.CodeAnalysis;
using System.Drawing.Text;
using System.Globalization;
using System.Runtime.CompilerServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.GdiPlus;
namespace System.Drawing
{
[NullableContext(1)]
[Nullable(0)]
public sealed class FontFamily : MarshalByRefObject, IDisposable, IPointer<GpFontFamily>
{
private const ushort NeutralLanguage = 0;
[Nullable(0)]
private unsafe GpFontFamily* _nativeFamily;
private bool _fromInstalledFontCollection;
unsafe IntPtr IPointer<GpFontFamily>.Pointer {
get {
return (IntPtr)_nativeFamily;
}
}
[Nullable(0)]
internal unsafe GpFontFamily* NativeFamily {
[NullableContext(0)]
get {
return _nativeFamily;
}
}
public string Name => GetName(CultureInfo.CurrentUICulture.LCID);
public static FontFamily[] Families => InstalledFontCollection.Instance.Families;
public unsafe static FontFamily GenericSansSerif => new FontFamily(GetGdipGenericSansSerif(), true);
public static FontFamily GenericSerif => new FontFamily(GenericFontFamilies.Serif);
public static FontFamily GenericMonospace => new FontFamily(GenericFontFamilies.Monospace);
[NullableContext(0)]
private unsafe void SetNativeFamily(GpFontFamily* family)
{
_nativeFamily = family;
}
[NullableContext(0)]
internal unsafe FontFamily(GpFontFamily* family, bool fromInstalledFontCollection)
{
_fromInstalledFontCollection = fromInstalledFontCollection;
if (fromInstalledFontCollection)
GC.SuppressFinalize(this);
else {
GpFontFamily* ptr = default(GpFontFamily*);
PInvokeGdiPlus.GdipCloneFontFamily(family, &ptr).ThrowIfFailed();
family = ptr;
}
SetNativeFamily(family);
}
internal unsafe FontFamily Clone()
{
if (_fromInstalledFontCollection)
return this;
return new FontFamily(_nativeFamily, false);
}
[NullableContext(0)]
internal FontFamily(ReadOnlySpan<char> name, bool createDefaultOnFail)
{
CreateFontFamily(name, null, createDefaultOnFail);
}
public FontFamily(string name)
{
CreateFontFamily(name.OrThrowIfNull("name").AsSpan(), null, false);
}
public FontFamily(string name, [Nullable(2)] FontCollection fontCollection)
{
CreateFontFamily(name.OrThrowIfNull("name").AsSpan(), fontCollection, false);
}
[NullableContext(0)]
private unsafe void CreateFontFamily(ReadOnlySpan<char> name, [Nullable(2)] FontCollection fontCollection, bool createDefaultOnFail = false)
{
GpFontCollection* ptr = fontCollection.Pointer();
_fromInstalledFontCollection = (ptr == null || ptr == InstalledFontCollection.Instance.Pointer());
Status status = Status.Ok;
GpFontFamily* gdipGenericSansSerif = default(GpFontFamily*);
fixed (char* value = &name.GetPinnableReference()) {
status = PInvokeGdiPlus.GdipCreateFontFamilyFromName(value, ptr, &gdipGenericSansSerif);
}
if (status != 0) {
if (createDefaultOnFail)
gdipGenericSansSerif = GetGdipGenericSansSerif();
else {
switch (status) {
case Status.FontFamilyNotFound:
throw new ArgumentException(System.SR.Format(System.SR.GdiplusFontFamilyNotFound, name.ToString()));
case Status.NotTrueTypeFont:
throw new ArgumentException(System.SR.Format(System.SR.GdiplusNotTrueTypeFont, name.ToString()));
}
status.ThrowIfFailed();
}
}
if (_fromInstalledFontCollection)
GC.SuppressFinalize(this);
GC.KeepAlive(fontCollection);
SetNativeFamily(gdipGenericSansSerif);
}
public unsafe FontFamily(GenericFontFamilies genericFamily)
{
GpFontFamily* nativeFamily = default(GpFontFamily*);
switch (genericFamily) {
case GenericFontFamilies.Serif:
PInvokeGdiPlus.GdipGetGenericFontFamilySerif(&nativeFamily).ThrowIfFailed();
break;
case GenericFontFamilies.SansSerif:
PInvokeGdiPlus.GdipGetGenericFontFamilySansSerif(&nativeFamily).ThrowIfFailed();
break;
default:
PInvokeGdiPlus.GdipGetGenericFontFamilyMonospace(&nativeFamily).ThrowIfFailed();
break;
}
_fromInstalledFontCollection = true;
SetNativeFamily(nativeFamily);
}
~FontFamily()
{
Dispose(false);
}
public override string ToString()
{
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(9, 2);
defaultInterpolatedStringHandler.AppendLiteral("[");
defaultInterpolatedStringHandler.AppendFormatted("FontFamily");
defaultInterpolatedStringHandler.AppendLiteral(": Name=");
defaultInterpolatedStringHandler.AppendFormatted(Name);
defaultInterpolatedStringHandler.AppendLiteral("]");
return defaultInterpolatedStringHandler.ToStringAndClear();
}
[NullableContext(2)]
public unsafe override bool Equals([NotNullWhen(true)] object obj)
{
if (obj == this)
return true;
FontFamily fontFamily = obj as FontFamily;
if (fontFamily == null)
return false;
return fontFamily.NativeFamily == NativeFamily;
}
public unsafe override int GetHashCode()
{
Span<char> span = new Span<char>(stackalloc byte[64], 32);
GetName(span, 0);
return string.GetHashCode(span.SliceAtFirstNull());
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private unsafe void Dispose(bool disposing)
{
if (_nativeFamily != null && !_fromInstalledFontCollection) {
PInvokeGdiPlus.GdipDeleteFontFamily(_nativeFamily);
_nativeFamily = null;
}
}
public unsafe string GetName(int language)
{
Span<char> span = new Span<char>(stackalloc byte[64], 32);
GetName(span, (ushort)language);
return new string(span.SliceAtFirstNull());
}
[NullableContext(0)]
private unsafe void GetName(Span<char> span, ushort language)
{
fixed (char* value = &span.GetPinnableReference()) {
PInvokeGdiPlus.GdipGetFamilyName(NativeFamily, value, language).ThrowIfFailed();
}
}
[NullableContext(0)]
private unsafe static GpFontFamily* GetGdipGenericSansSerif()
{
GpFontFamily* result = default(GpFontFamily*);
PInvokeGdiPlus.GdipGetGenericFontFamilySansSerif(&result).ThrowIfFailed();
return result;
}
[Obsolete("FontFamily.GetFamilies has been deprecated. Use Families instead.")]
public static FontFamily[] GetFamilies(Graphics graphics)
{
ArgumentNullException.ThrowIfNull(graphics, "graphics");
return InstalledFontCollection.Instance.Families;
}
public unsafe bool IsStyleAvailable(FontStyle style)
{
BOOL value = default(BOOL);
PInvokeGdiPlus.GdipIsStyleAvailable(NativeFamily, (int)style, &value).ThrowIfFailed();
GC.KeepAlive(this);
return value;
}
public unsafe int GetEmHeight(FontStyle style)
{
ushort result = default(ushort);
PInvokeGdiPlus.GdipGetEmHeight(NativeFamily, (int)style, &result).ThrowIfFailed();
GC.KeepAlive(this);
return result;
}
public unsafe int GetCellAscent(FontStyle style)
{
ushort result = default(ushort);
PInvokeGdiPlus.GdipGetCellAscent(NativeFamily, (int)style, &result).ThrowIfFailed();
GC.KeepAlive(this);
return result;
}
public unsafe int GetCellDescent(FontStyle style)
{
ushort result = default(ushort);
PInvokeGdiPlus.GdipGetCellDescent(NativeFamily, (int)style, &result).ThrowIfFailed();
GC.KeepAlive(this);
return result;
}
public unsafe int GetLineSpacing(FontStyle style)
{
ushort result = default(ushort);
PInvokeGdiPlus.GdipGetLineSpacing(NativeFamily, (int)style, &result).ThrowIfFailed();
GC.KeepAlive(this);
return result;
}
}
}