94 lines
3.4 KiB
C#
94 lines
3.4 KiB
C#
// Copyright (c) Six Labors.
|
|
// Licensed under the Six Labors Split License.
|
|
|
|
using System;
|
|
using System.Buffers;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using static SixLabors.Fonts.Native.CoreFoundation;
|
|
using static SixLabors.Fonts.Native.CoreText;
|
|
|
|
namespace SixLabors.Fonts.Native {
|
|
/// <summary>
|
|
/// An enumerator that enumerates over available macOS system fonts.
|
|
/// The enumerated strings are the absolute paths to the font files.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Internally, it calls the native CoreText's <see cref="CTFontManagerCopyAvailableFontURLs"/> method to retrieve
|
|
/// the list of fonts so using this class must be guarded by <c>RuntimeInformation.IsOSPlatform(OSPlatform.OSX)</c>.
|
|
/// </remarks>
|
|
internal sealed class MacSystemFontsEnumerator : IEnumerable<string>, IEnumerator<string>
|
|
{
|
|
private static readonly ArrayPool<byte> BytePool = ArrayPool<byte>.Shared;
|
|
|
|
private readonly IntPtr fontUrls;
|
|
private readonly bool releaseFontUrls;
|
|
private int fontIndex;
|
|
|
|
public MacSystemFontsEnumerator()
|
|
: this(CTFontManagerCopyAvailableFontURLs(), releaseFontUrls: true, fontIndex: 0)
|
|
{
|
|
}
|
|
|
|
private MacSystemFontsEnumerator(IntPtr fontUrls, bool releaseFontUrls, int fontIndex)
|
|
{
|
|
if (fontUrls == IntPtr.Zero)
|
|
{
|
|
throw new ArgumentException($"The {nameof(fontUrls)} must not be NULL.", nameof(fontUrls));
|
|
}
|
|
|
|
this.fontUrls = fontUrls;
|
|
this.releaseFontUrls = releaseFontUrls;
|
|
this.fontIndex = fontIndex;
|
|
|
|
this.Current = null!;
|
|
}
|
|
|
|
public string Current { get; private set; }
|
|
|
|
object IEnumerator.Current => this.Current;
|
|
|
|
public bool MoveNext()
|
|
{
|
|
Debug.Assert(CFGetTypeID(this.fontUrls) == CFArrayGetTypeID(), "The fontUrls array must be a CFArrayRef");
|
|
if (this.fontIndex < CFArrayGetCount(this.fontUrls))
|
|
{
|
|
IntPtr fontUrl = CFArrayGetValueAtIndex(this.fontUrls, this.fontIndex);
|
|
Debug.Assert(CFGetTypeID(fontUrl) == CFURLGetTypeID(), "The elements of the fontUrls array must be a CFURLRef");
|
|
IntPtr fontPath = CFURLCopyFileSystemPath(fontUrl, CFURLPathStyle.kCFURLPOSIXPathStyle);
|
|
|
|
int fontPathLength = (int)CFStringGetLength(fontPath);
|
|
int fontPathBufferSize = (fontPathLength + 1) * 2; // +1 for the NULL byte and *2 for UTF-16
|
|
byte[] fontPathBuffer = BytePool.Rent(fontPathBufferSize);
|
|
CFStringGetCString(fontPath, fontPathBuffer, fontPathBufferSize, CFStringEncoding.kCFStringEncodingUTF16LE);
|
|
this.Current = Encoding.Unicode.GetString(fontPathBuffer, 0, fontPathBufferSize - 2); // -2 for the UTF-16 NULL
|
|
BytePool.Return(fontPathBuffer);
|
|
|
|
CFRelease(fontPath);
|
|
|
|
this.fontIndex++;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void Reset() => this.fontIndex = 0;
|
|
|
|
public void Dispose()
|
|
{
|
|
if (this.releaseFontUrls)
|
|
{
|
|
CFRelease(this.fontUrls);
|
|
}
|
|
}
|
|
|
|
public IEnumerator<string> GetEnumerator() => new MacSystemFontsEnumerator(this.fontUrls, releaseFontUrls: false, this.fontIndex);
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
|
}
|
|
}
|