// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace SixLabors.Fonts { /// /// Defines a group of type faces having a similar basic design and certain /// variations in styles. /// public struct FontFamily : IEquatable { private readonly IReadOnlyFontMetricsCollection collection; /// /// Initializes a new instance of the struct. /// /// The name. /// The collection. /// The culture the family was extracted against internal FontFamily(string name, IReadOnlyFontMetricsCollection collection, CultureInfo culture) { Guard.NotNull(collection, nameof(collection)); this.collection = collection; this.Name = name; this.Culture = culture; } /// /// Gets the name. /// public string Name { get; } /// /// Gets the culture this instance was extracted against. /// public CultureInfo Culture { get; } /// /// Compares two objects for equality. /// /// The on the left side of the operand. /// The on the right side of the operand. /// /// if the current left is equal to the /// parameter; otherwise, . /// public static bool operator ==(FontFamily left, FontFamily right) => left.Equals(right); /// /// Compares two objects for inequality. /// /// The on the left side of the operand. /// The on the right side of the operand. /// /// if the current left is unequal to the /// parameter; otherwise, . /// public static bool operator !=(FontFamily left, FontFamily right) => !(left == right); /// /// Create a new instance of the for the named font family with regular styling. /// /// The size of the font in PT units. /// The new . public readonly Font CreateFont(float size) { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } return new Font(this, size); } /// /// Create a new instance of the for the named font family. /// /// The size of the font in PT units. /// The font style. /// The new . public readonly Font CreateFont(float size, FontStyle style) { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } return new Font(this, size, style); } /// /// Create a new instance of the for the named font family with regular styling /// and the specified variation axis settings. /// /// The size of the font in PT units. /// The variation axis settings to apply. /// The new . public readonly Font CreateFont(float size, params FontVariation[] variations) { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } Font baseFont = new(this, size); return variations.Length > 0 ? new Font(baseFont, variations) : baseFont; } /// /// Create a new instance of the for the named font family with the specified /// style and variation axis settings. /// /// The size of the font in PT units. /// The font style. /// The variation axis settings to apply. /// The new . public readonly Font CreateFont(float size, FontStyle style, params FontVariation[] variations) { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } Font baseFont = new(this, size, style); return variations.Length > 0 ? new Font(baseFont, variations) : baseFont; } /// /// Gets the collection of that are currently available. /// /// A read-only memory region containing the available font styles. public readonly ReadOnlyMemory GetAvailableStyles() { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } return this.collection.GetAllStyles(this.Name, this.Culture); } /// /// Gets the collection of filesystem paths to the font family sources. /// /// /// When this method returns, contains the filesystem paths to the font family sources, /// if the path exists; otherwise, an empty memory region. /// This parameter is passed uninitialized. /// /// /// if the was created via filesystem paths; otherwise, . /// public bool TryGetPaths(out ReadOnlyMemory paths) { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } ReadOnlySpan styles = this.GetAvailableStyles().Span; string[]? filePaths = null; int pathCount = 0; foreach (FontStyle style in styles) { if (this.collection.TryGetMetrics(this.Name, this.Culture, style, out FontMetrics? metrics) && metrics is FileFontMetrics fileMetrics) { filePaths ??= new string[styles.Length]; filePaths[pathCount++] = fileMetrics.Path; } } paths = pathCount > 0 ? new ReadOnlyMemory(filePaths!, 0, pathCount) : ReadOnlyMemory.Empty; return !paths.IsEmpty; } /// /// Gets the specified font metrics matching the given font style. /// /// The font style to use when searching for a match. /// /// When this method returns, contains the metrics associated with the specified name, /// if the name is found; otherwise, the default value for the type of the metrics parameter. /// This parameter is passed uninitialized. /// /// /// if the contains font metrics /// with the specified name; otherwise, . /// public readonly bool TryGetMetrics(FontStyle style, [NotNullWhen(true)] out FontMetrics? metrics) { if (this == default) { FontsThrowHelper.ThrowDefaultInstance(); } return this.collection.TryGetMetrics(this.Name, this.Culture, style, out metrics); } /// public override bool Equals(object? obj) => obj is FontFamily family && this.Equals(family); /// public readonly bool Equals(FontFamily other) { StringComparer comparer = StringComparerHelpers.GetCaseInsensitiveStringComparer(this.Culture); return comparer.Equals(this.Name, other.Name) && EqualityComparer.Default.Equals(this.Culture, other.Culture) && EqualityComparer.Default.Equals(this.collection, other.collection); } /// public override readonly int GetHashCode() => HashCode.Combine(this.collection, this.Name, this.Culture); /// public override readonly string ToString() => this.Name; } }