// 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;
}
}