RUMBLE does not support other mod managers. If you want to use a manager, you must use the RUMBLE Mod Manager, a manager specifically designed for this game.
Decompiled source of Fontifier v1.1.4
Mods/Fontifier.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Fontifier; using HarmonyLib; using Il2CppTMPro; using MelonLoader; using RumbleModUI; using RumbleModUIPlus; using RumbleModdingAPI; using Semver; using SixLabors.Fonts; using UnityEngine; using UnityEngine.TextCore.LowLevel; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(global::Fontifier.Fontifier), "Fontifier", "1.1.4", "ninjaguardian", "https://thunderstore.io/c/rumble/p/ninjaguardian/Fontifier")] [assembly: MelonGame("Buckethead Entertainment", "RUMBLE")] [assembly: MelonColor(255, 0, 160, 230)] [assembly: MelonAuthorColor(255, 0, 160, 230)] [assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)] [assembly: VerifyLoaderVersion("0.7.0", true)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ninjaguardian (github)")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025 ninjaguardian (github), This work is dedicated to the public domain under CC0 1.0.")] [assembly: AssemblyDescription("Lets you change the font for other mods")] [assembly: AssemblyFileVersion("1.1.4.0")] [assembly: AssemblyInformationalVersion("1.1.4")] [assembly: AssemblyProduct("Fontifier")] [assembly: AssemblyTitle("Fontifier")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ninjaguardian/Fontifier")] [assembly: AssemblyVersion("1.1.4.0")] namespace Fontifier; public static class FontifierModInfo { public const string ModName = "Fontifier"; public const string ModVer = "1.1.4"; public const string ModSchemaVer = "1.0.0"; public const string MLVersion = "0.7.0"; } public class FontNameValidator : ValidationParameters { public override bool DoValidation(string Input) { if (string.IsNullOrWhiteSpace(Input)) { return true; } foreach (TMP_FontAsset font in Fontifier.fonts) { if (((Object)font).name.Equals(Input, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } public class Fontifier : MelonMod { private static class TournamentScoringPatch { public static MethodBase TargetMethod(MelonMod mod) { return ((object)mod).GetType().GetMethod("SpawnScoreboard", BindingFlags.Instance | BindingFlags.NonPublic); } public static void Postfix() { TextMeshPro val = TournamentScoreboardText(); if ((Object)(object)val != (Object)null) { ((TMP_Text)val).font = TournamentScoringFont(arg: true); } } public static HarmonyMethod GetPostfix() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return new HarmonyMethod(typeof(TournamentScoringPatch).GetMethod("Postfix")); } } private static class MatchInfoPatch { public static MethodBase TargetMethod(MelonMod mod) { return ((object)mod).GetType().GetMethod("RunInit", BindingFlags.Instance | BindingFlags.NonPublic); } public static void Postfix(MelonMod __instance) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown Type type = ((object)__instance).GetType(); TMP_FontAsset font = MatchInfoFont(arg: true); MatchInfoGameObject = (GameObject)(type.GetField("matchInfoGameObject", BindingFlags.Static | BindingFlags.Public)?.GetValue(null)); if ((Object)(object)MatchInfoGameObject == (Object)null) { Logger.Warning("MatchInfo's matchInfoGameObject is null"); } else { foreach (TextMeshPro componentsInChild in MatchInfoGameObject.GetComponentsInChildren<TextMeshPro>(true)) { ((TMP_Text)componentsInChild).font = font; } } MatchInfoGymGameObject = (GameObject)(type.GetField("gymMatchInfoGameObject", BindingFlags.Static | BindingFlags.Public)?.GetValue(null)); if ((Object)(object)MatchInfoGymGameObject == (Object)null) { Logger.Warning("MatchInfo's gymMatchInfoGameObject is null"); return; } ((TMP_Text)MatchInfoGymGameObject.GetComponent<TextMeshPro>()).font = font; foreach (TextMeshPro componentsInChild2 in MatchInfoGymGameObject.GetComponentsInChildren<TextMeshPro>(true)) { ((TMP_Text)componentsInChild2).font = font; } } public static HarmonyMethod GetPostfix() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return new HarmonyMethod(typeof(MatchInfoPatch).GetMethod("Postfix")); } } private const string ModDesc = "Enter a font from the Font List or leave it empty to use the default font.\n\nMake sure to hit enter!"; private static Instance _logger; public static readonly List<TMP_FontAsset> fonts = new List<TMP_FontAsset>(); private static readonly Mod ModUI = new Mod(); private static readonly Tags tags = new Tags(); private static readonly FontNameValidator validator = new FontNameValidator(); private static TMP_FontAsset DefaultFont; private static readonly Dictionary<string, Dictionary<string, TMP_FontAsset>> modFontCache = new Dictionary<string, Dictionary<string, TMP_FontAsset>>(); private static Func<bool, TMP_FontAsset> TournamentScoringFont; private static Func<TextMeshPro> TournamentScoreboardText; private static Func<bool, TMP_FontAsset> MatchInfoFont; private static GameObject MatchInfoGameObject; private static GameObject MatchInfoGymGameObject; public static Instance Logger { get { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Expected O, but got Unknown //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Expected O, but got Unknown if (_logger != null) { return _logger; } Type type = Type.GetType("MelonLoader.Properties.BuildInfo, MelonLoader") ?? Type.GetType("MelonLoader.BuildInfo, MelonLoader"); if (type == null) { Instance val = new Instance("Fontifier"); val.Error("Could not find MelonLoader.BuildInfo or MelonLoader.Properties.BuildInfo."); return val; } object obj = type.GetProperty("VersionNumber", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); if (obj == null) { Instance val2 = new Instance("Fontifier"); val2.Error("Could not get MelonLoader version."); return val2; } if (SemVersion.Equals(SemVersion.Parse("0.7.0", false), (SemVersion)obj)) { dynamic val3 = Type.GetType("System.Drawing.Color, System.Drawing.Common")?.GetMethod("FromArgb", BindingFlags.Static | BindingFlags.Public, null, new Type[4] { typeof(int), typeof(int), typeof(int), typeof(int) }, null)?.Invoke(null, new object[4] { 255, 0, 160, 230 }); if (val3 != null) { _logger = new Instance("Fontifier", val3); return _logger; } Instance val4 = new Instance("Fontifier"); val4.Error("Detected MelonLoader 0.7.0 but couldn't use System.Drawing.Common"); return val4; } dynamic val5 = Type.GetType("MelonLoader.Logging.ColorARGB, MelonLoader").GetMethod("FromArgb", BindingFlags.Static | BindingFlags.Public, null, new Type[4] { typeof(byte), typeof(byte), typeof(byte), typeof(byte) }, null)?.Invoke(null, new object[4] { byte.MaxValue, (byte)0, (byte)160, (byte)230 }); if (val5 != null) { _logger = new Instance("Fontifier", val5); return _logger; } Instance val6 = new Instance("Fontifier"); val6.Error("Detected MelonLoader 0.7.1+ but couldn't use MelonLoader.Logging.ColorARGB"); return val6; } } [Obsolete("Can caused unintended side effects. Use FontFromNameCopy if possible.")] public static TMP_FontAsset FontFromName(string fontName) { if (string.IsNullOrWhiteSpace(fontName)) { return DefaultFont; } TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)fonts).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => string.Equals(((Object)f).name, fontName, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null) { Logger.Warning("Font with name " + fontName + " is not loaded"); return DefaultFont; } return val; } public static TMP_FontAsset FontFromNameCopy(string modName, string fontName, bool cache) { if (cache && modFontCache.TryGetValue(modName, out var value) && value.TryGetValue(fontName, out var value2)) { return value2; } TMP_FontAsset obj = FontFromName(fontName); string name = ((Object)obj).name; TMP_FontAsset val = DuplicateFont(obj); if ((Object)(object)val == (Object)null) { val = DuplicateFont(DefaultFont); if ((Object)(object)val == (Object)null) { return null; } name = ((Object)DefaultFont).name; } ((Object)val).name = "[" + modName + "] " + name; if (cache) { if (!modFontCache.ContainsKey(modName)) { modFontCache[modName] = new Dictionary<string, TMP_FontAsset>(); } modFontCache[modName][fontName] = val; } return val; } public static TMP_FontAsset DuplicateFont(TMP_FontAsset currentFont) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)currentFont == (Object)null) { return null; } TMP_FontAsset val; if (!string.IsNullOrWhiteSpace(currentFont.m_SourceFontFilePath) && File.Exists(currentFont.m_SourceFontFilePath)) { val = TMP_FontAsset.CreateFontAsset(currentFont.m_SourceFontFilePath, 0, 90, currentFont.atlasPadding, currentFont.atlasRenderMode, currentFont.atlasWidth, currentFont.atlasHeight, currentFont.atlasPopulationMode, currentFont.isMultiAtlasTexturesEnabled); } else { if (!((Object)(object)currentFont.m_SourceFontFile != (Object)null)) { Logger.BigError("Font named " + ((Object)currentFont).name + " does not have a source."); return null; } val = TMP_FontAsset.CreateFontAsset(currentFont.m_SourceFontFile, 0, 90, currentFont.atlasPadding, currentFont.atlasRenderMode, currentFont.atlasWidth, currentFont.atlasHeight, currentFont.atlasPopulationMode, currentFont.isMultiAtlasTexturesEnabled); } ((Object)val).hideFlags = ((Object)currentFont).hideFlags; ((Object)val).name = ((Object)currentFont).name + " (duplicated)"; return val; } public override void OnInitializeMelon() { DefaultFont = TMP_FontAsset.CreateFontAsset(Calls.LoadAssetFromStream<Font>((MelonMod)(object)this, "Fontifier.gooddogfont", "GOODDP__"), 0, 90, 5, (GlyphRenderMode)4165, 1024, 1024, (AtlasPopulationMode)1, true); ((Object)DefaultFont).hideFlags = (HideFlags)61; ((Object)DefaultFont).name = "Default - GOODDP__"; } public override void OnLateInitializeMelon() { UI.instance.UI_Initialized += OnUIInitialized; } private void OnUIInitialized() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown ((Mod)ModUI).ModName = "Fontifier"; ((Mod)ModUI).ModVersion = "1.1.4"; ModUI.ModFormatVersion = "1.0.0"; ((Mod)ModUI).SetFolder("Fontifier"); ModUI.AddDescriptionAtStart("Description", "", "Lets you change the font for other mods.", new Tags { IsSummary = true }); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string item in from f in Directory.EnumerateFiles("UserData\\Fontifier\\fonts", "*.*", SearchOption.TopDirectoryOnly) where f.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".otf", StringComparison.OrdinalIgnoreCase) select f) { try { TMP_FontAsset val = TMP_FontAsset.CreateFontAsset(item, 0, 90, 5, (GlyphRenderMode)4165, 1024, 1024); ((Object)val).hideFlags = (HideFlags)61; string text; try { FontFamily val2 = new FontCollection().Add(item); text = ((FontFamily)(ref val2)).Name; if (string.IsNullOrWhiteSpace(text)) { throw new Exception("Font has no internal family name"); } } catch (Exception ex) { Logger.Error("Could not read internal font name for " + item + ", using filename instead.", ex); text = Path.GetFileNameWithoutExtension(item); } if (string.IsNullOrWhiteSpace(text)) { throw new Exception("Font has an invalid name/filename"); } string text2 = text; int num = 0; while (hashSet.Contains(text2)) { num++; text2 = $"{text} ({num})"; } ((Object)val).name = text2; hashSet.Add(((Object)val).name); fonts.Add(val); } catch (Exception ex2) { Logger.Error("Failed to load font from " + item, ex2); } } ModUI.AddDescriptionAtIndex("Fonts List", "", "The following fonts are loaded:\n" + string.Join("\n", fonts.Select((TMP_FontAsset f) => ((Object)f).name)), new Tags { IsEmpty = true }, 1); foreach (MelonMod mod in MelonTypeBase<MelonMod>.RegisteredMelons) { if (((MelonBase)mod).Info.Name.Equals("RUMBLE Tournament Scoring", StringComparison.OrdinalIgnoreCase)) { FieldInfo scoreboardText = ((object)mod).GetType().GetField("scoreboardText", BindingFlags.Instance | BindingFlags.NonPublic); if (scoreboardText == null) { Logger.Warning("RUMBLE Tournament Scoring's scoreboardText FieldInfo is null"); continue; } TournamentScoreboardText = () => (TextMeshPro)scoreboardText.GetValue(mod); TournamentScoringFont = RegisterModWithReferenceCopy("RUMBLE Tournament Scoring", TournamentScoringChanged); ((MelonBase)this).HarmonyInstance.Patch(TournamentScoringPatch.TargetMethod(mod), (HarmonyMethod)null, TournamentScoringPatch.GetPostfix(), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (((MelonBase)mod).Info.Name.Equals("MatchInfo", StringComparison.OrdinalIgnoreCase)) { MatchInfoFont = RegisterModWithReferenceCopy("MatchInfo", MatchInfoChanged); ((MelonBase)this).HarmonyInstance.Patch(MatchInfoPatch.TargetMethod(mod), (HarmonyMethod)null, MatchInfoPatch.GetPostfix(), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } ((Mod)ModUI).GetFromFile(); UI.instance.AddMod((Mod)(object)ModUI); } private static void TournamentScoringChanged(object sender, EventArgs args) { TextMeshPro val = TournamentScoreboardText(); if ((Object)(object)val != (Object)null) { ((TMP_Text)val).font = FontFromNameCopy("RUMBLE Tournament Scoring", ((ValueChange<string>)(object)args)?.Value, cache: true); } } private static void MatchInfoChanged(object sender, EventArgs args) { TMP_FontAsset font = FontFromNameCopy("MatchInfo", ((ValueChange<string>)(object)args)?.Value, cache: true); if ((Object)(object)MatchInfoGameObject != (Object)null) { foreach (TextMeshPro componentsInChild in MatchInfoGameObject.GetComponentsInChildren<TextMeshPro>(true)) { ((TMP_Text)componentsInChild).font = font; } } if (!((Object)(object)MatchInfoGymGameObject != (Object)null)) { return; } ((TMP_Text)MatchInfoGymGameObject.GetComponent<TextMeshPro>()).font = font; foreach (TextMeshPro componentsInChild2 in MatchInfoGymGameObject.GetComponentsInChildren<TextMeshPro>(true)) { ((TMP_Text)componentsInChild2).font = font; } } private static ModSetting<string> RegisterModBase(string modName, EventHandler<EventArgs> valueChanged) { ModSetting<string> obj = ((Mod)ModUI).AddToList(modName, "", "Enter a font from the Font List or leave it empty to use the default font.\n\nMake sure to hit enter!", tags); ((Mod)ModUI).AddValidation(modName, (ValidationParameters)(object)validator); ((ModSetting)obj).CurrentValueChanged += valueChanged; return obj; } [Obsolete("Can caused unintended side effects. Use RegisterModCopy if possible.")] public static (Func<TMP_FontAsset>, Func<string, TMP_FontAsset>) RegisterMod(string modName, EventHandler<EventArgs> valueChanged) { ModSetting<string> setting = RegisterModBase(modName, valueChanged); return (() => FontFromName((string)((ModSetting)setting).Value), FontFromName); } public static (Func<bool, TMP_FontAsset>, Func<string, bool, TMP_FontAsset>) RegisterModCopy(string modName, EventHandler<EventArgs> valueChanged) { ModSetting<string> setting = RegisterModBase(modName, valueChanged); return ((bool cache) => FontFromNameCopy(modName, (string)((ModSetting)setting).Value, cache), (string fontName, bool cache) => FontFromNameCopy(modName, fontName, cache)); } private static ModSetting<string> RegisterModWithReferenceBase(string modName, EventHandler<EventArgs> valueChanged) { ModSetting<string> obj = ((Mod)ModUI).AddToList(modName, "", "Enter a font from the Font List or leave it empty to use the default font.\n\nMake sure to hit enter!", tags); ((Mod)ModUI).AddValidation(modName, (ValidationParameters)(object)validator); ((ModSetting)obj).CurrentValueChanged += valueChanged; return obj; } [Obsolete("Can caused unintended side effects. Use RegisterModWithReferenceCopy if possible.")] public static Func<TMP_FontAsset> RegisterModWithReference(string modName, EventHandler<EventArgs> valueChanged) { ModSetting<string> setting = RegisterModWithReferenceBase(modName, valueChanged); return () => FontFromName((string)((ModSetting)setting).Value); } public static Func<bool, TMP_FontAsset> RegisterModWithReferenceCopy(string modName, EventHandler<EventArgs> valueChanged) { ModSetting<string> setting = RegisterModWithReferenceBase(modName, valueChanged); return (bool cache) => FontFromNameCopy(modName, (string)((ModSetting)setting).Value, cache); } }
UserLibs/SixLabors.Fonts.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers; using System.Buffers.Binary; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Numerics; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using Microsoft.CodeAnalysis; using SixLabors.Fonts; using SixLabors.Fonts.IO; using SixLabors.Fonts.Native; using SixLabors.Fonts.Tables; using SixLabors.Fonts.Tables.AdvancedTypographic; using SixLabors.Fonts.Tables.AdvancedTypographic.GPos; using SixLabors.Fonts.Tables.AdvancedTypographic.GSub; using SixLabors.Fonts.Tables.AdvancedTypographic.Shapers; using SixLabors.Fonts.Tables.Cff; using SixLabors.Fonts.Tables.General; using SixLabors.Fonts.Tables.General.CMap; using SixLabors.Fonts.Tables.General.Colr; using SixLabors.Fonts.Tables.General.Kern; using SixLabors.Fonts.Tables.General.Name; using SixLabors.Fonts.Tables.General.Post; using SixLabors.Fonts.Tables.TrueType; using SixLabors.Fonts.Tables.TrueType.Glyphs; using SixLabors.Fonts.Tables.TrueType.Hinting; using SixLabors.Fonts.Tables.Woff; using SixLabors.Fonts.Unicode; using SixLabors.Fonts.Unicode.Resources; using SixLabors.Fonts.Utilities; using SixLabors.Fonts.WellKnownIds; using UnicodeTrieGenerator.StateAutomation; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("Six Labors")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Six Labors")] [assembly: AssemblyDescription("A cross-platform library for loading and laying out fonts for processing and measuring; written in C#")] [assembly: AssemblyFileVersion("2.1.3.0")] [assembly: AssemblyInformationalVersion("2.1.3+eadc8dbc041d1b335ecf790ce400b5e069f075de")] [assembly: AssemblyProduct("SixLabors.Fonts")] [assembly: AssemblyTitle("SixLabors.Fonts")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/SixLabors/Fonts")] [assembly: NeutralResourcesLanguage("en")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] [assembly: InternalsVisibleTo("SixLabors.Fonts.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000147e6fe6766715eec6cfed61f1e7dcdbf69748a3e355c67e9d8dfd953acab1d5e012ba34b23308166fdc61ee1d0390d5f36d814a6091dd4b5ed9eda5a26afced924c683b4bfb4b3d64b0586a57eff9f02b1f84e3cb0ddd518bd1697f2c84dcbb97eb8bb5c7801be12112ed0ec86db934b0e9a5171e6bb1384b6d2f7d54dfa97")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace UnicodeTrieGenerator.StateAutomation { internal class StateMachine { private const int InitialState = 1; private const int FailState = 0; public int[][] StateTable { get; } public bool[] Accepting { get; } public string[][] Tags { get; } public StateMachine(int[][] stateTable, bool[] accepting, string[][] tags) { StateTable = stateTable; Accepting = accepting; Tags = tags; } public IEnumerable<StateMatch> Match(ReadOnlySpan<int> input) { int num = 1; int? num2 = null; int? num3 = null; List<StateMatch> list = new List<StateMatch>(input.Length); for (int i = 0; i < input.Length; i++) { int num4 = input[i]; int num5 = num; num = StateTable[num][num4]; if (num == 0) { if (num2.HasValue && num3.HasValue && num3 >= num2) { list.Add(new StateMatch { StartIndex = num2.Value, EndIndex = num3.Value, Tags = Tags[num5] }); } num = StateTable[1][num4]; num2 = null; } if (num != 0 && !num2.HasValue) { num2 = i; } if (Accepting[num]) { num3 = i; } if (num == 0) { num = 1; } } if (num2.HasValue && num3.HasValue && num3 >= num2) { list.Add(new StateMatch { StartIndex = num2.Value, EndIndex = num3.Value, Tags = Tags[num] }); } return list; } public void Apply(int[] input, Dictionary<string, Action<int, int, ArraySlice<int>>> actions) { foreach (StateMatch item in Match(input)) { foreach (string tag in item.Tags) { if (actions.TryGetValue(tag, out Action<int, int, ArraySlice<int>> value)) { value(item.StartIndex, item.EndIndex, new ArraySlice<int>(input, item.StartIndex, item.EndIndex + 1 - item.StartIndex)); } } } } } internal class StateMatch : IEquatable<StateMatch?> { public int StartIndex { get; set; } public int EndIndex { get; set; } public IList<string> Tags { get; set; } = Array.Empty<string>(); public override bool Equals(object? obj) { return Equals(obj as StateMatch); } public bool Equals(StateMatch? other) { if (other != null && StartIndex == other.StartIndex && EndIndex == other.EndIndex) { return Tags.SequenceEqual(other.Tags); } return false; } public override int GetHashCode() { return HashCode.Combine(StartIndex, EndIndex, Tags); } } internal interface INode : IEnumerable<INode>, IEnumerable { HashSet<INode> FollowPos { get; } bool Nullable { get; } int Count { get; } INode this[int index] { get; set; } void CalcFollowPos(); INode Copy(); } internal interface ILogicalNode : INode, IEnumerable<INode>, IEnumerable { HashSet<INode> FirstPos { get; } HashSet<INode> LastPos { get; } } internal abstract class Node : INode, IEnumerable<INode>, IEnumerable { protected List<INode> Enumerator { get; } = new List<INode>(); public HashSet<INode> FollowPos { get; } = new HashSet<INode>(); public virtual bool Nullable => false; public int Count => Enumerator.Count; public INode this[int index] { get { return Enumerator[index]; } set { Enumerator[index] = value; } } public virtual void CalcFollowPos() { using IEnumerator<INode> enumerator = GetEnumerator(); while (enumerator.MoveNext()) { enumerator.Current.CalcFollowPos(); } } public abstract INode Copy(); public IEnumerator<INode> GetEnumerator() { return Enumerator.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal class Variable : Node, ILogicalNode, INode, IEnumerable<INode>, IEnumerable { public string Name { get; } HashSet<INode> ILogicalNode.FirstPos { get; } = new HashSet<INode>(); HashSet<INode> ILogicalNode.LastPos { get; } = new HashSet<INode>(); public Variable(string name) { Name = name; } public override INode Copy() { return new Variable(Name); } } internal class Comment : Node { public string Value { get; } public Comment(string value) { Value = value; } public override INode Copy() { return new Comment(Value); } } internal class Assignment : Node { public Variable Variable => (Variable)base[0]; public ILogicalNode Expression => (ILogicalNode)base[1]; public Assignment(Variable variable, ILogicalNode expression) { base.Enumerator.Add(variable); base.Enumerator.Add(expression); } public override INode Copy() { return new Assignment(Variable, Expression); } } internal class Alternation : Node, ILogicalNode, INode, IEnumerable<INode>, IEnumerable { public ILogicalNode A => (ILogicalNode)base[0]; public ILogicalNode B => (ILogicalNode)base[1]; public override bool Nullable { get { if (!A.Nullable) { return B.Nullable; } return true; } } public HashSet<INode> FirstPos => NodeUtilities.Union(A.FirstPos, B.FirstPos); public HashSet<INode> LastPos => NodeUtilities.Union(A.LastPos, B.LastPos); public Alternation(ILogicalNode a, ILogicalNode b) { base.Enumerator.Add(a); base.Enumerator.Add(b); } public override INode Copy() { return new Alternation((ILogicalNode)A.Copy(), (ILogicalNode)B.Copy()); } } internal class Concatenation : Node, ILogicalNode, INode, IEnumerable<INode>, IEnumerable { public ILogicalNode A => (ILogicalNode)base[0]; public ILogicalNode B => (ILogicalNode)base[1]; public override bool Nullable { get { if (A.Nullable) { return B.Nullable; } return false; } } public HashSet<INode> FirstPos { get { HashSet<INode> hashSet = A.FirstPos; if (A.Nullable) { hashSet = NodeUtilities.Union(hashSet, B.FirstPos); } return hashSet; } } public HashSet<INode> LastPos { get { HashSet<INode> hashSet = B.LastPos; if (B.Nullable) { hashSet = NodeUtilities.Union(hashSet, A.LastPos); } return hashSet; } } public Concatenation(ILogicalNode a, ILogicalNode b) { base.Enumerator.Add(a); base.Enumerator.Add(b); } public override void CalcFollowPos() { base.CalcFollowPos(); foreach (INode lastPo in A.LastPos) { NodeUtilities.AddAll(lastPo.FollowPos, B.FirstPos); } } public override INode Copy() { return new Concatenation((ILogicalNode)A.Copy(), (ILogicalNode)B.Copy()); } } internal class Repeat : Node, ILogicalNode, INode, IEnumerable<INode>, IEnumerable { public ILogicalNode Expression => (ILogicalNode)base[0]; public string Op { get; } public override bool Nullable { get { string op = Op; if (op == "*" || op == "?") { return true; } return false; } } public HashSet<INode> FirstPos => Expression.FirstPos; public HashSet<INode> LastPos => Expression.LastPos; public Repeat(ILogicalNode expression, string op) { base.Enumerator.Add(expression); Op = op; } public override void CalcFollowPos() { base.CalcFollowPos(); string op = Op; if ((!(op == "*") && !(op == "+")) || 1 == 0) { return; } foreach (INode lastPo in LastPos) { NodeUtilities.AddAll(lastPo.FollowPos, FirstPos); } } public override INode Copy() { return new Repeat((ILogicalNode)Expression.Copy(), Op); } } internal abstract class Leaf : Node, ILogicalNode, INode, IEnumerable<INode>, IEnumerable { public HashSet<INode> FirstPos => new HashSet<INode> { this }; public HashSet<INode> LastPos => new HashSet<INode> { this }; } internal class Literal : Leaf { public int Value { get; } public Literal(int value) { Value = value; } public override INode Copy() { return new Literal(Value); } } internal class EndMarker : Leaf { public override INode Copy() { throw new NotImplementedException(); } } internal class Tag : Leaf { public string Name { get; } public override bool Nullable => true; public Tag(string value) { Name = value; } public override INode Copy() { return new Tag(Name); } } internal static class NodeUtilities { public static ILogicalNode BuildRepetition(ILogicalNode expression, int min, double max = double.PositiveInfinity) { if (min < 0 || (double)min > max) { throw new ArgumentOutOfRangeException("min", $"Invalid repetition range: {min} {max}"); } ILogicalNode logicalNode = null; for (int i = 0; i < min; i++) { logicalNode = Concat(logicalNode, (ILogicalNode)expression.Copy()); } if (max == double.PositiveInfinity) { logicalNode = Concat(logicalNode, new Repeat((ILogicalNode)expression.Copy(), "*")); } else { for (int j = min; (double)j < max; j++) { logicalNode = Concat(logicalNode, new Repeat((ILogicalNode)expression.Copy(), "?")); } } return logicalNode; } public static ILogicalNode Concat(ILogicalNode? a, ILogicalNode b) { if (a == null) { return b; } return new Concatenation(a, b); } public static HashSet<INode> Union(HashSet<INode> a, HashSet<INode> b) { HashSet<INode> hashSet = new HashSet<INode>(a); AddAll(hashSet, b); return hashSet; } public static void AddAll(HashSet<INode> a, HashSet<INode> b) { foreach (INode item in b) { a.Add(item); } } public static bool Equal(ICollection<INode> a, ICollection<INode> b) { if (a == b) { return true; } if (a.Count != b.Count) { return false; } foreach (INode item in a) { if (!b.Contains(item)) { return false; } } return true; } } internal class SymbolTable { public Dictionary<string, ILogicalNode> Variables { get; set; } = new Dictionary<string, ILogicalNode>(); public Dictionary<string, int> Symbols { get; set; } = new Dictionary<string, int>(); public int Size { get; set; } public SymbolTable(IList<INode> statements, Dictionary<string, int> externalSymbols) { Size = 0; AddExternalSymbols(externalSymbols); Process(statements); } public ILogicalNode Main() { if (!Variables.TryGetValue("Main", out ILogicalNode value)) { throw new InvalidOperationException("No 'Main' variable declaration found"); } return value; } private void AddExternalSymbols(Dictionary<string, int> externalSymbols) { foreach (string key in externalSymbols.Keys) { int value = externalSymbols[key]; Variables[key] = new Literal(value); Symbols[key] = value; Size++; } } private void Process(IList<INode> statements) { foreach (INode statement in statements) { if (statement is Assignment assignment) { Variables[assignment.Variable.Name] = (ILogicalNode)ProcessExpression(assignment.Expression); if (assignment.Expression is Literal literal) { Symbols[assignment.Variable.Name] = literal.Value; Size++; } } } } private INode ProcessExpression(INode expression) { for (int i = 0; i < expression.Count; i++) { expression[i] = ProcessExpression(expression[i]); } if (expression is Variable variable) { ILogicalNode logicalNode = Variables[variable.Name]; expression = ProcessExpression(logicalNode.Copy()); } return expression; } } } namespace SixLabors { [DebuggerStepThrough] internal static class DebugGuard { [Conditional("DEBUG")] public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression("value")] string? parameterName = null) where TValue : class { ArgumentNullException.ThrowIfNull(value, parameterName); } [Conditional("DEBUG")] public static void NotNullOrWhiteSpace([NotNull] string? value, [CallerArgumentExpression("value")] string? paramName = null) { ArgumentNullException.ThrowIfNull(value, "value"); if (string.IsNullOrWhiteSpace(value)) { ThrowArgumentException("Must not be empty or whitespace.", paramName); } } [Conditional("DEBUG")] public static void MustBeLessThan<TValue>(TValue value, TValue max, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(max) >= 0) { ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); } } [Conditional("DEBUG")] public static void MustBeLessThanOrEqualTo<TValue>(TValue value, TValue max, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(max) > 0) { ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); } } [Conditional("DEBUG")] public static void MustBeGreaterThan<TValue>(TValue value, TValue min, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(min) <= 0) { ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than {min}."); } } [Conditional("DEBUG")] public static void MustBeGreaterThanOrEqualTo<TValue>(TValue value, TValue min, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(min) < 0) { ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); } } [Conditional("DEBUG")] public static void MustBeBetweenOrEqualTo<TValue>(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) { ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); } } [Conditional("DEBUG")] public static void IsTrue(bool target, string parameterName, string message) { if (!target) { ThrowArgumentException(message, parameterName); } } [Conditional("DEBUG")] public static void IsFalse(bool target, string parameterName, string message) { if (target) { ThrowArgumentException(message, parameterName); } } [Conditional("DEBUG")] public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength, string parameterName) { if (source.Length < minLength) { ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName); } } [Conditional("DEBUG")] public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName) { if (source.Length < minLength) { ThrowArgumentException($"The size must be at least {minLength}.", parameterName); } } [Conditional("DEBUG")] public static void DestinationShouldNotBeTooShort<TSource, TDest>(ReadOnlySpan<TSource> source, Span<TDest> destination, string destinationParamName) { if (destination.Length < source.Length) { ThrowArgumentException("Destination span is too short!", destinationParamName); } } [Conditional("DEBUG")] public static void DestinationShouldNotBeTooShort<TSource, TDest>(Span<TSource> source, Span<TDest> destination, string destinationParamName) { if (destination.Length < source.Length) { ThrowArgumentException("Destination span is too short!", destinationParamName); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowArgumentException(string message, string parameterName) { throw new ArgumentException(message, parameterName); } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowArgumentOutOfRangeException(string parameterName, string message) { throw new ArgumentOutOfRangeException(parameterName, message); } } [DebuggerStepThrough] internal static class Guard { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression("value")] string? parameterName = null) where TValue : class { ArgumentNullException.ThrowIfNull(value, parameterName); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotNullOrWhiteSpace([NotNull] string? value, string parameterName) { if (string.IsNullOrWhiteSpace(value)) { ThrowHelper.ThrowArgumentExceptionForNotNullOrWhitespace(value, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan<TValue>(TValue value, TValue max, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(max) >= 0) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo<TValue>(TValue value, TValue max, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(max) > 0) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan<TValue>(TValue value, TValue min, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(min) <= 0) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo<TValue>(TValue value, TValue min, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(min) < 0) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo<TValue>(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable<TValue> { if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void IsTrue(bool target, string parameterName, string message) { if (!target) { ThrowHelper.ThrowArgumentException(message, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void IsFalse(bool target, string parameterName, string message) { if (target) { ThrowHelper.ThrowArgumentException(message, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength, string parameterName) { if (source.Length < minLength) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName) { if (source.Length < minLength) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void DestinationShouldNotBeTooShort<TSource, TDest>(ReadOnlySpan<TSource> source, Span<TDest> destination, string destinationParamName) { if (destination.Length < source.Length) { ThrowHelper.ThrowArgumentException("Destination span is too short!", destinationParamName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void DestinationShouldNotBeTooShort<TSource, TDest>(Span<TSource> source, Span<TDest> destination, string destinationParamName) { if (destination.Length < source.Length) { ThrowHelper.ThrowArgumentException("Destination span is too short!", destinationParamName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(byte value, byte max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(byte value, byte max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(byte value, byte min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(byte value, byte min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(byte value, byte min, byte max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(sbyte value, sbyte max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(sbyte value, sbyte max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(sbyte value, sbyte min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(sbyte value, sbyte min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(sbyte value, sbyte min, sbyte max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(short value, short max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(short value, short max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(short value, short min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(short value, short min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(short value, short min, short max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(ushort value, ushort max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(ushort value, ushort max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(ushort value, ushort min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(ushort value, ushort min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(ushort value, ushort min, ushort max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(char value, char max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(char value, char max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(char value, char min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(char value, char min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(char value, char min, char max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(int value, int max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(int value, int max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(int value, int min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(int value, int min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(int value, int min, int max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(uint value, uint max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(uint value, uint max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(uint value, uint min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(uint value, uint min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(uint value, uint min, uint max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(float value, float max, string parameterName) { if (!(value < max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(float value, float max, string parameterName) { if (!(value <= max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(float value, float min, string parameterName) { if (!(value > min)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(float value, float min, string parameterName) { if (!(value >= min)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(float value, float min, float max, string parameterName) { if (!(value >= min) || !(value <= max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(long value, long max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(long value, long max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(long value, long min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(long value, long min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(long value, long min, long max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(ulong value, ulong max, string parameterName) { if (value >= max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(ulong value, ulong max, string parameterName) { if (value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(ulong value, ulong min, string parameterName) { if (value <= min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(ulong value, ulong min, string parameterName) { if (value < min) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(ulong value, ulong min, ulong max, string parameterName) { if (value < min || value > max) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(double value, double max, string parameterName) { if (!(value < max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(double value, double max, string parameterName) { if (!(value <= max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(double value, double min, string parameterName) { if (!(value > min)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(double value, double min, string parameterName) { if (!(value >= min)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(double value, double min, double max, string parameterName) { if (!(value >= min) || !(value <= max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThan(decimal value, decimal max, string parameterName) { if (!(value < max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeLessThanOrEqualTo(decimal value, decimal max, string parameterName) { if (!(value <= max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThan(decimal value, decimal min, string parameterName) { if (!(value > min)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeGreaterThanOrEqualTo(decimal value, decimal min, string parameterName) { if (!(value >= min)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MustBeBetweenOrEqualTo(decimal value, decimal min, decimal max, string parameterName) { if (!(value >= min) || !(value <= max)) { ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); } } } internal static class ThrowHelper { [DoesNotReturn] public static void ThrowArgumentExceptionForNotNullOrWhitespace(string? value, string name) { if (value == null) { ThrowArgumentNullException(name, "Parameter \"" + name + "\" must be not null."); } else { ThrowArgumentException(name, "Parameter \"" + name + "\" must not be empty or whitespace."); } } [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForMustBeLessThan<T>(T value, T max, string name) { ThrowArgumentOutOfRangeException(name, $"Parameter \"{name}\" ({typeof(T)}) must be less than {max}, was {value}"); } [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo<T>(T value, T maximum, string name) { ThrowArgumentOutOfRangeException(name, $"Parameter \"{name}\" ({typeof(T)}) must be less than or equal to {maximum}, was {value}"); } [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan<T>(T value, T minimum, string name) { ThrowArgumentOutOfRangeException(name, $"Parameter \"{name}\" ({typeof(T)}) must be greater than {minimum}, was {value}"); } [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo<T>(T value, T minimum, string name) { ThrowArgumentOutOfRangeException(name, $"Parameter \"{name}\" ({typeof(T)}) must be greater than or equal to {minimum}, was {value}"); } [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo<T>(T value, T minimum, T maximum, string name) { ThrowArgumentOutOfRangeException(name, $"Parameter \"{name}\" ({typeof(T)}) must be between or equal to {minimum} and {maximum}, was {value}"); } [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(int minLength, string parameterName) { ThrowArgumentException($"Spans must be at least of length {minLength}!", parameterName); } [DoesNotReturn] public static void ThrowArgumentException(string message, string name) { throw new ArgumentException(message, name); } [DoesNotReturn] public static void ThrowArgumentNullException(string name, string message) { throw new ArgumentNullException(name, message); } [DoesNotReturn] public static void ThrowArgumentOutOfRangeException(string name, string message) { throw new ArgumentOutOfRangeException(name, message); } } } namespace SixLabors.Fonts { internal struct ArrayBuilder<T> where T : struct { private const int DefaultCapacity = 4; private const int MaxCoreClrArrayLength = 2146435071; private T[]? data; private int size; public int Length { readonly get { return size; } set { if (value != size) { if (value > 0) { EnsureCapacity(value); size = value; } else { size = 0; } } } } public readonly ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ref data[index]; } } public ArrayBuilder(int capacity) { this = default(ArrayBuilder<T>); Guard.MustBeGreaterThanOrEqualTo(capacity, 0, "capacity"); data = new T[capacity]; } public void Add(T item) { int num = size; Length++; data[num] = item; } public ArraySlice<T> Add(int length, bool clear = true) { int num = size; Length += length; ArraySlice<T> result = AsSlice(num, Length - num); if (clear) { result.Span.Clear(); } return result; } public ArraySlice<T> Add(in ReadOnlyArraySlice<T> value) { int num = size; Length += value.Length; ArraySlice<T> arraySlice = AsSlice(num, Length - num); value.CopyTo(arraySlice); return arraySlice; } public void Clear() { size = 0; } private void EnsureCapacity(int min) { T[]? array = data; int num = ((array != null) ? array.Length : 0); if (num < min) { uint num2 = ((num == 0) ? 4u : ((uint)(num * 2))); if (num2 > 2146435071) { num2 = 2146435071u; } if (num2 < min) { num2 = (uint)min; } T[] destinationArray = new T[num2]; if (size > 0) { Array.Copy(data, destinationArray, size); } data = destinationArray; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ArraySlice<T> AsSlice() { return AsSlice(Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ArraySlice<T> AsSlice(int length) { return new ArraySlice<T>(data, 0, length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ArraySlice<T> AsSlice(int start, int length) { return new ArraySlice<T>(data, start, length); } } internal readonly struct ArraySlice<T> : IEnumerable<T>, IEnumerable where T : struct { public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable { private readonly T[]? array; private readonly int start; private readonly int end; private int current; public readonly T Current { get { if (current < start) { ThrowEnumNotStarted(); } if (current >= end) { ThrowEnumEnded(); } return array[current]; } } object? IEnumerator.Current => Current; internal Enumerator(ArraySlice<T> slice) { array = slice.data; start = slice.Start; end = slice.Start + slice.Length; current = slice.Start - 1; } public bool MoveNext() { if (current < end) { current++; return current < end; } return false; } void IEnumerator.Reset() { current = start - 1; } public readonly void Dispose() { } private static void ThrowEnumNotStarted() { throw new InvalidOperationException("Enumeration has not started. Call MoveNext."); } private static void ThrowEnumEnded() { throw new InvalidOperationException("Enumeration already finished."); } } private readonly T[] data; public static ArraySlice<T> Empty => new ArraySlice<T>(Array.Empty<T>()); public int Start { get; } public int Length { get; } public Span<T> Span { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Span<T>(data, Start, Length); } } public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ref Unsafe.Add(ref MemoryMarshal.GetReference(Span), index); } } public ArraySlice(T[] data) : this(data, 0, data.Length) { } public ArraySlice(T[] data, int start, int length) { this.data = data; Start = start; Length = length; } public static implicit operator ReadOnlyArraySlice<T>(ArraySlice<T> slice) { return new ReadOnlyArraySlice<T>(slice.data, slice.Start, slice.Length); } public static implicit operator ArraySlice<T>(T[] array) { return new ArraySlice<T>(array, 0, array.Length); } public void CopyTo(ArraySlice<T> destination) { Span.CopyTo(destination.Span); } public void Fill(T value) { Span.Fill(value); } public ArraySlice<T> Slice(int start, int length) { return new ArraySlice<T>(data, start, length); } public IEnumerator<T> GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } } [DebuggerDisplay("Start: {StartOfStream}, Position: {BaseStream.Position}")] internal sealed class BigEndianBinaryReader : IDisposable { private readonly byte[] buffer = new byte[16]; private readonly bool leaveOpen; private long StartOfStream { get; } public Stream BaseStream { get; } public BigEndianBinaryReader(Stream stream, bool leaveOpen) { BaseStream = stream; StartOfStream = stream.Position; this.leaveOpen = leaveOpen; } public void Seek(long offset, SeekOrigin origin) { if (origin == SeekOrigin.Begin) { offset += StartOfStream; } BaseStream.Seek(offset, origin); } public byte ReadByte() { ReadInternal(buffer, 1); return buffer[0]; } public sbyte ReadSByte() { ReadInternal(buffer, 1); return (sbyte)buffer[0]; } public float ReadF2dot14() { return (float)ReadInt16() / 16384f; } public short ReadInt16() { ReadInternal(buffer, 2); return BinaryPrimitives.ReadInt16BigEndian(buffer); } public TEnum ReadInt16<TEnum>() where TEnum : struct, Enum { TryConvert<ushort, TEnum>(ReadUInt16(), out var value); return value; } public short ReadFWORD() { return ReadInt16(); } public short[] ReadFWORDArray(int length) { return ReadInt16Array(length); } public ushort ReadUFWORD() { return ReadUInt16(); } public float ReadFixed() { ReadInternal(buffer, 4); return (float)BinaryPrimitives.ReadInt32BigEndian(buffer) / 65536f; } public int ReadInt32() { ReadInternal(buffer, 4); return BinaryPrimitives.ReadInt32BigEndian(buffer); } public long ReadInt64() { ReadInternal(buffer, 8); return BinaryPrimitives.ReadInt64BigEndian(buffer); } public ushort ReadUInt16() { ReadInternal(buffer, 2); return BinaryPrimitives.ReadUInt16BigEndian(buffer); } public ushort ReadOffset16() { return ReadUInt16(); } public TEnum ReadUInt16<TEnum>() where TEnum : struct, Enum { TryConvert<ushort, TEnum>(ReadUInt16(), out var value); return value; } public ushort[] ReadUInt16Array(int length) { ushort[] array = new ushort[length]; for (int i = 0; i < length; i++) { array[i] = ReadUInt16(); } return array; } public void ReadUInt16Array(Span<ushort> buffer) { for (int i = 0; i < buffer.Length; i++) { buffer[i] = ReadUInt16(); } } public uint[] ReadUInt32Array(int length) { uint[] array = new uint[length]; for (int i = 0; i < length; i++) { array[i] = ReadUInt32(); } return array; } public byte[] ReadUInt8Array(int length) { byte[] array = new byte[length]; ReadInternal(array, length); return array; } public short[] ReadInt16Array(int length) { short[] array = new short[length]; for (int i = 0; i < length; i++) { array[i] = ReadInt16(); } return array; } public void ReadInt16Array(Span<short> buffer) { for (int i = 0; i < buffer.Length; i++) { buffer[i] = ReadInt16(); } } public byte ReadUInt8() { ReadInternal(buffer, 1); return buffer[0]; } public int ReadUInt24() { return (ReadByte() << 16) | ReadUInt16(); } public uint ReadUInt32() { ReadInternal(buffer, 4); return BinaryPrimitives.ReadUInt32BigEndian(buffer); } public uint ReadOffset32() { return ReadUInt32(); } public byte[] ReadBytes(int count) { byte[] array = new byte[count]; int num; for (int i = 0; i < count; i += num) { num = BaseStream.Read(array, i, count - i); if (num == 0) { byte[] array2 = new byte[i]; Buffer.BlockCopy(array, 0, array2, 0, i); return array2; } } return array; } public string ReadString(int bytesToRead, Encoding encoding) { byte[] array = new byte[bytesToRead]; ReadInternal(array, bytesToRead); return encoding.GetString(array, 0, array.Length); } public string ReadTag() { ReadInternal(buffer, 4); return Encoding.UTF8.GetString(buffer, 0, 4); } public int ReadOffset(int size) { return size switch { 1 => ReadByte(), 2 => (ReadByte() << 8) | ReadByte(), 3 => (ReadByte() << 16) | (ReadByte() << 8) | ReadByte(), 4 => (ReadByte() << 24) | (ReadByte() << 16) | (ReadByte() << 8) | ReadByte(), _ => throw new InvalidOperationException(), }; } private void ReadInternal(byte[] data, int size) { int num; for (int i = 0; i < size; i += num) { num = BaseStream.Read(data, i, size - i); if (num == 0) { throw new EndOfStreamException($"End of stream reached with {size - i} byte{((size - i == 1) ? "s" : string.Empty)} left to read."); } } } public void Dispose() { if (!leaveOpen) { BaseStream?.Dispose(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvert<T, TEnum>(T input, out TEnum value) where T : struct, IConvertible, IFormattable, IComparable where TEnum : struct, Enum { if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<TEnum>()) { value = Unsafe.As<T, TEnum>(ref input); return true; } value = default(TEnum); return false; } } internal readonly struct Bounds : IEquatable<Bounds> { public static Bounds Empty; public Vector2 Min { get; } public Vector2 Max { get; } public Bounds(Vector2 min, Vector2 max) { Min = Vector2.Min(min, max); Max = Vector2.Max(min, max); } public Bounds(float minX, float minY, float maxX, float maxY) : this(new Vector2(minX, minY), new Vector2(maxX, maxY)) { } public static bool operator ==(Bounds left, Bounds right) { return left.Equals(right); } public static bool operator !=(Bounds left, Bounds right) { return !(left == right); } public Vector2 Size() { return Max - Min; } public static Bounds Load(BigEndianBinaryReader reader) { short num = reader.ReadInt16(); short num2 = reader.ReadInt16(); short num3 = reader.ReadInt16(); short num4 = reader.ReadInt16(); return new Bounds(num, num2, num3, num4); } public static Bounds Load(IList<ControlPoint> controlPoints) { if (controlPoints == null || controlPoints.Count == 0) { return Empty; } float num = float.MaxValue; float num2 = float.MaxValue; float num3 = float.MinValue; float num4 = float.MinValue; for (int i = 0; i < controlPoints.Count; i++) { Vector2 point = controlPoints[i].Point; if (point.X < num) { num = point.X; } if (point.X > num3) { num3 = point.X; } if (point.Y < num2) { num2 = point.Y; } if (point.Y > num4) { num4 = point.Y; } } return new Bounds(num, num2, num3, num4); } public static Bounds Transform(in Bounds bounds, Matrix3x2 matrix) { return new Bounds(Vector2.Transform(bounds.Min, matrix), Vector2.Transform(bounds.Max, matrix)); } public override bool Equals(object? obj) { if (obj is Bounds other) { return Equals(other); } return false; } public bool Equals(Bounds other) { if (Min.Equals(other.Min)) { return Max.Equals(other.Max); } return false; } public override int GetHashCode() { return HashCode.Combine(Min, Max); } } internal ref struct Buffer<T> where T : unmanaged { private int length; private readonly byte[] buffer; private readonly Span<T> span; private bool isDisposed; public Memory<T> Memory { get; } public Buffer(int length) { Guard.MustBeGreaterThanOrEqualTo(length, 0, "length"); int num = Unsafe.SizeOf<T>(); int minimumLength = length * num; buffer = ArrayPool<byte>.Shared.Rent(minimumLength); this.length = length; using ByteMemoryManager<T> byteMemoryManager = new ByteMemoryManager<T>(buffer); Memory<T> memory = byteMemoryManager.Memory; Memory = memory.Slice(0, this.length); memory = Memory; span = memory.Span; isDisposed = false; } public readonly Span<T> GetSpan() { if (buffer == null) { ThrowObjectDisposedException(); } return span; } public void Dispose() { if (!isDisposed) { ArrayPool<byte>.Shared.Return(buffer); length = 0; isDisposed = true; } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowObjectDisposedException() { throw new ObjectDisposedException("Buffer<T>"); } } internal sealed class ByteMemoryManager<T> : MemoryManager<T> where T : unmanaged { private readonly Memory<byte> memory; public ByteMemoryManager(Memory<byte> memory) { this.memory = memory; } protected override void Dispose(bool disposing) { } public override Span<T> GetSpan() { return MemoryMarshal.Cast<byte, T>(memory.Span); } public override MemoryHandle Pin(int elementIndex = 0) { return memory.Slice(elementIndex * Unsafe.SizeOf<T>()).Pin(); } public override void Unpin() { } } [Flags] public enum ColorFontSupport { None = 0, MicrosoftColrFormat = 1 } public class FontException : Exception { public FontException(string message) : base(message) { } } public class FontFamilyNotFoundException : FontException { public string FontFamily { get; } public IReadOnlyCollection<string> SearchDirectories { get; } public FontFamilyNotFoundException(string family) : this(family, (IReadOnlyCollection<string>)(object)Array.Empty<string>()) { } public FontFamilyNotFoundException(string family, IReadOnlyCollection<string> searchDirectories) : base(GetMessage(family, searchDirectories)) { FontFamily = family; SearchDirectories = searchDirectories; } private static string GetMessage(string family, IReadOnlyCollection<string> searchDirectories) { if (searchDirectories.Count == 0) { return "The \"" + family + "\" font family could not be found"; } if (searchDirectories.Count == 1) { return "The \"" + family + "\" font family could not be found in the following directory: " + searchDirectories.First(); } return $"The \"{family}\" font family could not be found in the following directories:{Environment.NewLine}{string.Join(Environment.NewLine, searchDirectories.Select((string e) => " * " + e))}"; } } internal static class FontsThrowHelper { [MethodImpl(MethodImplOptions.NoInlining)] public static T ThrowGlyphMissingException<T>(CodePoint codePoint) { throw new GlyphMissingException(codePoint); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowDefaultInstance() { throw new FontException("Cannot use the default value type instance to create a font."); } } public class GlyphMissingException : FontException { public GlyphMissingException(CodePoint codePoint) : base("Cannot find a glyph for the code point '" + codePoint.ToDebuggerDisplay() + "'") { } } public class InvalidFontFileException : Exception { public InvalidFontFileException(string message) : base(message) { } } public class InvalidFontTableException : InvalidFontFileException { public string Table { get; } public InvalidFontTableException(string message, string table) : base(message) { Table = table; } } public class MissingFontTableException : InvalidFontFileException { public string Table { get; } public MissingFontTableException(string message, string table) : base(message) { Table = table; } } internal sealed class FileFontMetrics : FontMetrics { private readonly Lazy<StreamFontMetrics> fontMetrics; public override FontDescription Description { get; } public string Path { get; } public override ushort UnitsPerEm => fontMetrics.Value.UnitsPerEm; public override float ScaleFactor => fontMetrics.Value.ScaleFactor; public override HorizontalMetrics HorizontalMetrics => fontMetrics.Value.HorizontalMetrics; public override VerticalMetrics VerticalMetrics => fontMetrics.Value.VerticalMetrics; public override short SubscriptXSize => fontMetrics.Value.SubscriptXSize; public override short SubscriptYSize => fontMetrics.Value.SubscriptYSize; public override short SubscriptXOffset => fontMetrics.Value.SubscriptXOffset; public override short SubscriptYOffset => fontMetrics.Value.SubscriptYOffset; public override short SuperscriptXSize => fontMetrics.Value.SuperscriptXSize; public override short SuperscriptYSize => fontMetrics.Value.SuperscriptYSize; public override short SuperscriptXOffset => fontMetrics.Value.SuperscriptXOffset; public override short SuperscriptYOffset => fontMetrics.Value.SuperscriptYOffset; public override short StrikeoutSize => fontMetrics.Value.StrikeoutSize; public override short StrikeoutPosition => fontMetrics.Value.StrikeoutPosition; public override short UnderlinePosition => fontMetrics.Value.UnderlinePosition; public override short UnderlineThickness => fontMetrics.Value.UnderlineThickness; public override float ItalicAngle => fontMetrics.Value.ItalicAngle; public FileFontMetrics(string path) : this(path, 0L) { } public FileFontMetrics(string path, long offset) : this(FontDescription.LoadDescription(path), path, offset) { } internal FileFontMetrics(FontDescription description, string path, long offset) { string path2 = path; base..ctor(); Description = description; Path = path2; fontMetrics = new Lazy<StreamFontMetrics>(() => StreamFontMetrics.LoadFont(path2, offset), isThreadSafe: true); } internal override bool TryGetGlyphId(CodePoint codePoint, out ushort glyphId) { return fontMetrics.Value.TryGetGlyphId(codePoint, out glyphId); } internal override bool TryGetGlyphId(CodePoint codePoint, CodePoint? nextCodePoint, out ushort glyphId, out bool skipNextCodePoint) { return fontMetrics.Value.TryGetGlyphId(codePoint, nextCodePoint, out glyphId, out skipNextCodePoint); } internal override bool TryGetCodePoint(ushort glyphId, out CodePoint codePoint) { return fontMetrics.Value.TryGetCodePoint(glyphId, out codePoint); } internal override bool TryGetGlyphClass(ushort glyphId, [NotNullWhen(true)] out GlyphClassDef? glyphClass) { return fontMetrics.Value.TryGetGlyphClass(glyphId, out glyphClass); } internal override bool TryGetMarkAttachmentClass(ushort glyphId, [NotNullWhen(true)] out GlyphClassDef? markAttachmentClass) { return fontMetrics.Value.TryGetMarkAttachmentClass(glyphId, out markAttachmentClass); } public override bool TryGetGlyphMetrics(CodePoint codePoint, TextAttributes textAttributes, TextDecorations textDecorations, LayoutMode layoutMode, ColorFontSupport support, [NotNullWhen(true)] out IReadOnlyList<GlyphMetrics>? metrics) { return fontMetrics.Value.TryGetGlyphMetrics(codePoint, textAttributes, textDecorations, layoutMode, support, out metrics); } internal override IReadOnlyList<GlyphMetrics> GetGlyphMetrics(CodePoint codePoint, ushort glyphId, TextAttributes textAttributes, TextDecorations textDecorations, LayoutMode layoutMode, ColorFontSupport support) { return fontMetrics.Value.GetGlyphMetrics(codePoint, glyphId, textAttributes, textDecorations, layoutMode, support); } public override IReadOnlyList<CodePoint> GetAvailableCodePoints() { return fontMetrics.Value.GetAvailableCodePoints(); } internal override bool TryGetGSubTable([NotNullWhen(true)] out GSubTable? gSubTable) { return fontMetrics.Value.TryGetGSubTable(out gSubTable); } internal override void ApplySubstitution(GlyphSubstitutionCollection collection) { fontMetrics.Value.ApplySubstitution(collection); } internal override bool TryGetKerningOffset(ushort currentId, ushort nextId, out Vector2 vector) { return fontMetrics.Value.TryGetKerningOffset(currentId, nextId, out vector); } internal override void UpdatePositions(GlyphPositioningCollection collection) { fontMetrics.Value.UpdatePositions(collection); } public static FileFontMetrics[] LoadFontCollection(string path) { using FileStream fileStream = File.OpenRead(path); long position = fileStream.Position; using BigEndianBinaryReader reader = new BigEndianBinaryReader(fileStream, leaveOpen: true); TtcHeader ttcHeader = TtcHeader.Read(reader); FileFontMetrics[] array = new FileFontMetrics[ttcHeader.NumFonts]; for (int i = 0; i < ttcHeader.NumFonts; i++) { fileStream.Position = position + ttcHeader.OffsetTable[i]; FontDescription description = FontDescription.LoadDescription(fileStream); array[i] = new FileFontMetrics(description, path, ttcHeader.OffsetTable[i]); } return array; } } public sealed class Font { private readonly Lazy<FontMetrics?> metrics; private readonly Lazy<string> fontName; public FontFamily Family { get; } public string Name => fontName.Value; public float Size { get; } public FontMetrics FontMetrics => metrics.Value ?? throw new FontException("Font instance not found."); public bool IsBold => (FontMetrics.Description.Style & FontStyle.Bold) == FontStyle.Bold; public bool IsItalic => (FontMetrics.Description.Style & FontStyle.Italic) == FontStyle.Italic; internal FontStyle RequestedStyle { get; } public Font(FontFamily family, float size) : this(family, size, FontStyle.Regular) { } public Font(FontFamily family, float size, FontStyle style) { if (family == default(FontFamily)) { throw new ArgumentException("Cannot use the default value type instance to create a font.", "family"); } Family = family; RequestedStyle = style; Size = size; metrics = new Lazy<FontMetrics>(LoadInstanceInternal, isThreadSafe: true); fontName = new Lazy<string>(LoadFontName, isThreadSafe: true); } public Font(Font prototype, FontStyle style) { if (prototype == null) { throw new ArgumentNullException("prototype"); } this..ctor(prototype.Family, prototype.Size, style); } public Font(Font prototype, float size, FontStyle style) { if (prototype == null) { throw new ArgumentNullException("prototype"); } this..ctor(prototype.Family, size, style); } public Font(Font prototype, float size) : this(prototype.Family, size, prototype.RequestedStyle) { } public bool TryGetPath([NotNullWhen(true)] out string? path) { if (this == null) { FontsThrowHelper.ThrowDefaultInstance(); } if (FontMetrics is FileFontMetrics fileFontMetrics) { path = fileFontMetrics.Path; return true; } path = null; return false; } public bool TryGetGlyphs(CodePoint codePoint, [NotNullWhen(true)] out IReadOnlyList<Glyph>? glyphs) { return TryGetGlyphs(codePoint, TextAttributes.None, ColorFontSupport.None, out glyphs); } public bool TryGetGlyphs(CodePoint codePoint, ColorFontSupport support, [NotNullWhen(true)] out IReadOnlyList<Glyph>? glyphs) { return TryGetGlyphs(codePoint, TextAttributes.None, support, out glyphs); } public bool TryGetGlyphs(CodePoint codePoint, TextAttributes textAttributes, ColorFontSupport support, [NotNullWhen(true)] out IReadOnlyList<Glyph>? glyphs) { return TryGetGlyphs(codePoint, textAttributes, TextDecorations.None, LayoutMode.HorizontalTopBottom, support, out glyphs); } public bool TryGetGlyphs(CodePoint codePoint, TextAttributes textAttributes, LayoutMode layoutMode, ColorFontSupport support, [NotNullWhen(true)] out IReadOnlyList<Glyph>? glyphs) { return TryGetGlyphs(codePoint, textAttributes, TextDecorations.None, layoutMode, support, out glyphs); } public bool TryGetGlyphs(CodePoint codePoint, TextAttributes textAttributes, TextDecorations textDecorations, LayoutMode layoutMode, ColorFontSupport support, [NotNullWhen(true)] out IReadOnlyList<Glyph>? glyphs) { TextRun textRun = new TextRun { Start = 0, End = 1, Font = this, TextAttributes = textAttributes, TextDecorations = textDecorations }; if (FontMetrics.TryGetGlyphMetrics(codePoint, textAttributes, textDecorations, layoutMode, support, out IReadOnlyList<GlyphMetrics> readOnlyList)) { List<Glyph> list = new List<Glyph>(); foreach (GlyphMetrics item in readOnlyList) { list.Add(new Glyph(item.CloneForRendering(textRun), Size)); } glyphs = list; return true; } glyphs = null; return false; } public bool TryGetKerningOffset(Glyph current, Glyph next, float dpi, out Vector2 vector) { if (FontMetrics.TryGetKerningOffset(current.GlyphMetrics.GlyphId, next.GlyphMetrics.GlyphId, out vector)) { Vector2 vector2 = new Vector2(Size * dpi) / next.GlyphMetrics.ScaleFactor; vector *= vector2; return true; } return false; } private string LoadFontName() { return metrics.Value?.Description.FontName(Family.Culture) ?? string.Empty; } private FontMetrics? LoadInstanceInternal() { if (Family.TryGetMetrics(RequestedStyle, out FontMetrics result)) { return result; } if ((RequestedStyle & FontStyle.Italic) == FontStyle.Italic && Family.TryGetMetrics(FontStyle.Italic, out result)) { return result; } if ((RequestedStyle & FontStyle.Bold) == FontStyle.Bold && Family.TryGetMetrics(FontStyle.Bold, out result)) { return result; } IEnumerable<FontStyle> availableStyles = Family.GetAvailableStyles(); FontStyle style = ((!availableStyles.Contains(FontStyle.Regular)) ? availableStyles.First() : FontStyle.Regular); Family.TryGetMetrics(style, out result); return result; } } public sealed class FontCollection : IFontCollection, IReadOnlyFontCollection, IFontMetricsCollection, IReadOnlyFontMetricsCollection { private readonly HashSet<string> searchDirectories = new HashSet<string>(); private readonly HashSet<FontMetrics> metricsCollection = new HashSet<FontMetrics>(); public IEnumerable<FontFamily> Families => FamiliesByCultureImpl(CultureInfo.InvariantCulture); public FontCollection() : this((IReadOnlyCollection<string>)(object)Array.Empty<string>()) { } internal FontCollection(IReadOnlyCollection<string> searchDirectories) { Guard.NotNull(searchDirectories, "searchDirectories"); foreach (string searchDirectory in searchDirectories) { this.searchDirectories.Add(searchDirectory); } } public FontFamily Add(string path) { FontDescription description; return Add(path, out description); } public FontFamily Add(string path, out FontDescription description) { return AddImpl(path, CultureInfo.InvariantCulture, out description); } public FontFamily Add(Stream stream) { FontDescription description; return Add(stream, out description); } public FontFamily Add(Stream stream, out FontDescription description) { return AddImpl(stream, CultureInfo.InvariantCulture, out description); } public IEnumerable<FontFamily> AddCollection(string path) { IEnumerable<FontDescription> descriptions; return AddCollection(path, out descriptions); } public IEnumerable<FontFamily> AddCollection(string path, out IEnumerable<FontDescription> descriptions) { return AddCollectionImpl(path, CultureInfo.InvariantCulture, out descriptions); } public IEnumerable<FontFamily> AddCollection(Stream stream) { IEnumerable<FontDescription> descriptions; return AddCollection(stream, out descriptions); } public IEnumerable<FontFamily> AddCollection(Stream stream, out IEnumerable<FontDescription> descriptions) { return AddCollectionImpl(stream, CultureInfo.InvariantCulture, out descriptions); } public FontFamily Get(string name) { return Get(name, CultureInfo.InvariantCulture); } public bool TryGet(string name, out FontFamily family) { return TryGet(name, CultureInfo.InvariantCulture, out family); } public FontFamily Add(string path, CultureInfo culture) { FontDescription description; return AddImpl(path, culture, out description); } public FontFamily Add(string path, CultureInfo culture, out FontDescription description) { return AddImpl(path, culture, out description); } public FontFamily Add(Stream stream, CultureInfo culture) { FontDescription description; return AddImpl(stream, culture, out description); } public FontFamily Add(Stream stream, CultureInfo culture, out FontDescription description) { return AddImpl(stream, culture, out description); } public IEnumerable<FontFamily> AddCollection(string path, CultureInfo culture) { IEnumerable<FontDescription> descriptions; return AddCollection(path, culture, out descriptions); } public IEnumerable<FontFamily> AddCollection(string path, CultureInfo culture, out IEnumerable<FontDescription> descriptions) { return AddCollectionImpl(path, culture, out descriptions); } public IEnumerable<FontFamily> AddCollection(Stream stream, CultureInfo culture) { IEnumerable<FontDescription> descriptions; return AddCollection(stream, culture, out descriptions); } public IEnumerable<FontFamily> AddCollection(Stream stream, CultureInfo culture, out IEnumerable<FontDescription> descriptions) { return AddCollectionImpl(stream, culture, out descriptions); } public IEnumerable<FontFamily> GetByCulture(CultureInfo culture) { return FamiliesByCultureImpl(culture); } public FontFamily Get(string name, CultureInfo culture) { return GetImpl(name, culture); } public bool TryGet(string name, CultureInfo culture, out FontFamily family) { return TryGetImpl(name, culture, out family); } FontFamily IFontMetricsCollection.AddMetrics(FontMetrics metrics, CultureInfo culture) { ((IFontMetricsCollection)this).AddMetrics(metrics); return new FontFamily(metrics.Description.FontFamily(culture), this, culture); } void IFontMetricsCollection.AddMetrics(FontMetrics metrics) { Guard.NotNull(metrics, "metrics"); if (metrics.Description == null) { throw new ArgumentException("FontMetrics must have a Description.", "metrics"); } lock (metricsCollection) { metricsCollection.Add(metrics); } } bool IReadOnlyFontMetricsCollection.TryGetMetrics(string name, CultureInfo culture, FontStyle style, [NotNullWhen(true)] out FontMetrics? metrics) { metrics = ((IReadOnlyFontMetricsCollection)this).GetAllMetrics(name, culture).FirstOrDefault((FontMetrics x) => x.Description.Style == style); return metrics != null; } IEnumerable<FontMetrics> IReadOnlyFontMetricsCollection.GetAllMetrics(string name, CultureInfo culture) { CultureInfo culture2 = culture; string name2 = name; Guard.NotNull(name2, "name"); StringComparer comparer = StringComparerHelpers.GetCaseInsensitiveStringComparer(culture2); return metricsCollection.Where((FontMetrics x) => comparer.Equals(x.Description.FontFamily(culture2), name2)).ToArray(); } IEnumerable<FontStyle> IReadOnlyFontMetricsCollection.GetAllStyles(string name, CultureInfo culture) { return (from x in ((IReadOnlyFontMetricsCollection)this).GetAllMetrics(name, culture) select x.Description.Style).ToArray(); } IEnumerator<FontMetrics> IReadOnlyFontMetricsCollection.GetEnumerator() { return metricsCollection.GetEnumerator(); } internal void AddSearchDirectories(IEnumerable<string> directories) { foreach (string directory in directories) { searchDirectories.Add(directory); } } private FontFamily AddImpl(string path, CultureInfo culture, out FontDescription description) { FileFontMetrics fileFontMetrics = new FileFontMetrics(path); description = fileFontMetrics.Description; return ((IFontMetricsCollection)this).AddMetrics((FontMetrics)fileFontMetrics, culture); } private FontFamily AddImpl(Stream stream, CultureInfo culture, out FontDescription description) { StreamFontMetrics streamFontMetrics = StreamFontMetrics.LoadFont(stream); description = streamFontMetrics.Description; return ((IFontMetricsCollection)this).AddMetrics((FontMetrics)streamFontMetrics, culture); } private IEnumerable<FontFamily> AddCollectionImpl(string path, CultureInfo culture, out IEnumerable<FontDescription> descriptions) { FileFontMetrics[] array = FileFontMetrics.LoadFontCollection(path); FontDescription[] array2 = new FontDescription[array.Length]; HashSet<FontFamily> hashSet = new HashSet<FontFamily>(); for (int i = 0; i < array.Length; i++) { array2[i] = array[i].Description; FontFamily item = ((IFontMetricsCollection)this).AddMetrics((FontMetrics)array[i], culture); hashSet.Add(item); } descriptions = array2; return hashSet; } private IEnumerable<FontFamily> AddCollectionImpl(Stream stream, CultureInfo culture, out IEnumerable<FontDescription> descriptions) { long position = stream.Position; using BigEndianBinaryReader reader = new BigEndianBinaryReader(stream, leaveOpen: true); TtcHeader ttcHeader = TtcHeader.Read(reader); List<FontDescription> list = new List<FontDescription>((int)ttcHeader.NumFonts); HashSet<FontFamily> hashSet = new HashSet<FontFamily>(); for (int i = 0; i < ttcHeader.NumFonts; i++) { stream.Position = position + ttcHeader.OffsetTable[i]; StreamFontMetrics streamFontMetrics = StreamFontMetrics.LoadFont(stream); hashSet.Add(((IFontMetricsCollection)this).AddMetrics((FontMetrics)streamFontMetrics, culture)); FontDescription description = streamFontMetrics.Description; list.Add(description); } descriptions = list; return hashSet; } private IEnumerable<FontFamily> FamiliesByCultureImpl(CultureInfo culture) { CultureInfo culture2 = culture; return (from x in metricsCollection.Select((FontMetrics x) => x.Description.FontFamily(culture2)).Distinct() select new FontFamily(x, this, culture2)).ToArray(); } private bool TryGetImpl(string name, CultureInfo culture, out FontFamily family) { CultureInfo culture2 = culture; string name2 = name; Guard.NotNull(name2, "name"); StringComparer comparer = StringComparerHelpers.GetCaseInsensitiveStringComparer(culture2); string text = metricsCollection.Select((FontMetrics x) => x.Description.FontFamily(culture2)).FirstOrDefault((string x) => comparer.Equals(name2, x)); if (text != null) { family = new FontFamily(text, this, culture2); return true; } family = default(FontFamily); return false; } private FontFamily GetImpl(string name, CultureInfo culture) { if (TryGetImpl(name, culture, out var family)) { return family; } throw new FontFamilyNotFoundException(name, searchDirectories); } } public static class FontCollectionExtensions { public static FontCollection AddSystemFonts(this FontCollection collection) { foreach (FontMetrics item in (IReadOnlyFontMetricsCollection)SystemFonts.Collection) { ((IFontMetricsCollection)collection).AddMetrics(item); } collection.AddSearchDirectories(SystemFonts.Collection.SearchDirectories); return collection; } public static FontCollection AddSystemFonts(this FontCollection collection, Predicate<FontMetrics> match) { bool flag = false; foreach (FontMetrics item in (IReadOnlyFontMetricsCollection)SystemFonts.Collection) { bool flag2 = match(item); flag = flag || flag2; if (flag2) { ((IFontMetricsCollection)collection).AddMetrics(item); } } if (flag) { collection.AddSearchDirectories(SystemFonts.Collection.SearchDirectories); } return collection; } } public class FontDescription { private readonly NameTable nameTable; public FontStyle Style { get; } public string FontNameInvariantCulture { get; } public string FontFamilyInvariantCulture { get; } public string FontSubFamilyNameInvariantCulture { get; } internal FontDescription(NameTable nameTable, OS2Table? os2, HeadTable? head) { this.nameTable = nameTable; Style = ConvertStyle(os2, head); FontNameInvariantCulture = FontName(CultureInfo.InvariantCulture); FontFamilyInvariantCulture = FontFamily(CultureInfo.InvariantCulture); FontSubFamilyNameInvariantCulture = FontSubFamilyName(CultureInfo.InvariantCulture); } public string FontName(CultureInfo culture) { return nameTable.FontName(culture); } public string FontFamily(CultureInfo culture) { return nameTable.FontFamilyName(culture); } public string FontSubFamilyName(CultureInfo culture) { return nameTable.FontSubFamilyName(culture); } public string GetNameById(CultureInfo culture, KnownNameIds nameId) { return nameTable.GetNameById(culture, nameId); } public static FontDescription LoadDescription(string path) { Guard.NotNullOrWhiteSpace(path, "path"); using FileStream stream = File.OpenRead(path); using FontReader reader = new FontReader(stream); return LoadDescription(reader); } public static FontDescription LoadDescription(Stream stream) { Guard.NotNull(stream, "stream"); using FontReader reader = new FontReader(stream); return LoadDescription(reader); } internal static FontDescription LoadDescription(FontReader reader) { HeadTable head = reader.TryGetTable<HeadTable>(); OS2Table os = reader.TryGetTable<OS2Table>(); return new FontDescription(reader.GetTable<NameTable>(), os, head); } public static FontDescription[] LoadFontCollectionDescriptions(string path) { Guard.NotNullOrWhiteSpace(path, "path"); using FileStream stream = File.OpenRead(path); return LoadFontCollectionDescriptions(stream); } public static FontDescription[] LoadFontCollectionDescriptions(Stream stream) { long position = stream.Position; using BigEndianBinaryReader reader = new BigEndianBinaryReader(stream, leaveOpen: true); TtcHeader ttcHeader = TtcHeader.Read(reader); FontDescription[] array = new FontDescription[ttcHeader.NumFonts]; for (int i = 0; i < ttcHeader.NumFonts; i++) { stream.Position = position + ttcHeader.OffsetTable[i]; using FontReader reader2 = new FontReader(stream); array[i] = LoadDescription(reader2); } return array; } private static FontStyle ConvertStyle(OS2Table? os2, HeadTable? head) { FontStyle fontStyle = FontStyle.Regular; if (os2 != null) { if ((os2.FontStyle & OS2Table.FontStyleSelection.BOLD) == OS2Table.FontStyleSelection.BOLD) { fontStyle |= FontStyle.Bold; } if ((os2.FontStyle & OS2Table.FontStyleSelection.ITALIC) == OS2Table.FontStyleSelection.ITALIC) { fontStyle |= FontStyle.Italic; } } else if (head != null) { if ((head.MacStyle & HeadTable.HeadMacStyle.Bold) == HeadTable.HeadMacStyle.Bold) { fontStyle |= FontStyle.Bold; } if ((head.MacStyle & HeadTable.HeadMacStyle.Italic) == HeadTable.HeadMacStyle.Italic) { fontStyle |= FontStyle.Italic; } } return fontStyle; } } public struct FontFamily : IEquatable<FontFamily> { private readonly IReadOnlyFontMetricsCollection collection; public string Name { get; } public CultureInfo Culture { get; } internal FontFamily(string name, IReadOnlyFontMetricsCollection collection, CultureInfo culture) { Guard.NotNull(collection, "collection"); this.collection = collection; Name = name; Culture = culture; } public static bool operator ==(FontFamily left, FontFamily right) { return left.Equals(right); } public static bool operator !=(FontFamily left, FontFamily right) { return !(left == right); } public readonly Font CreateFont(float size) { if (this == default(FontFamily)) { FontsThrowHelper.ThrowDefaultInstance(); } return new Font(this, size); } public readonly Font CreateFont(float size, FontStyle style) { if (this == default(FontFamily)) { FontsThrowHelper.ThrowDefaultInstance(); } return new Font(this, size, style); } public readonly IEnumerable<FontStyle> GetAvailableStyles() { if (this == default(FontFamily)) { FontsThrowHelper.ThrowDefaultInstance(); } return collection.GetAllStyles(Name, Culture); } public bool TryGetPaths(out IEnumerable<string> paths) { if (this == default(FontFamily)) { FontsThrowHelper.ThrowDefaultInstance(); } List<string> list = new List<string>(); foreach (FontStyle availableStyle in GetAvailableStyles()) { if (collection.TryGetMetrics(Name, Culture, availableStyle, out FontMetrics metrics) && metrics is FileFontMetrics fileFontMetrics) { list.Add(fileFontMetrics.Path); } } paths = list; return list.Count > 0; } public readonly bool TryGetMetrics(FontStyle style, [NotNullWhen(true)] out FontMetrics? metrics) { if (this == default(FontFamily)) { FontsThrowHelper.ThrowDefaultInstance(); } return collection.TryGetMetrics(Name, Culture, style, out metrics); } public override bool Equals(object? obj) { if (obj is FontFamily other) { return Equals(other); } return false; } public readonly bool Equals(FontFamily other) { if (StringComparerHelpers.GetCaseInsensitiveStringComparer(Culture).Equals(Name, other.Name) && EqualityComparer<CultureInfo>.Default.Equals(Culture, other.Culture)) { return EqualityComparer<IReadOnlyFontMetricsCollection>.Default.Equals(collection, other.collection); } return false; } public override readonly int GetHashCode() { return HashCode.Combine(collection, Name, Culture); } public override readonly string ToString() { return Name; } } public abstract class FontMetrics { public abstract FontDescription Description { get; } public abstract ushort UnitsPerEm { get; } public abstract float ScaleFactor { get; } public abstract HorizontalMetrics HorizontalMetrics { get; } public abstract VerticalMetrics VerticalMetrics { get; } public abstract short SubscriptXSize { get; } public abstract short SubscriptYSize { get; } public abstract short SubscriptXOffset { get; } public abstract short SubscriptYOffset { get; } public abstract short SuperscriptXSize { get; } public abstract short SuperscriptYSize { get; } public abstract short SuperscriptXOffset { get; } public abstract short SuperscriptYOffset { get; } public abstract short StrikeoutSize { get; } public abstract short StrikeoutPosition { get; } public abstract short UnderlinePosition { get; } public abstract short UnderlineThickness { get; } public abstract float ItalicAngle { get; } internal FontMetrics() { } internal abstract bool TryGetGlyphId(CodePoint codePoint, out ushort glyphId); internal abstract bool TryGetGlyphId(CodePoint codePoint, CodePoint? nextCodePoint, out ushort glyphId, out bool skipNextCodePoint); internal abstract bool TryGetCodePoint(ushort glyphId, out CodePoint codePoint); internal abstract bool TryGetGlyphClass(ushort glyphId, [NotNullWhen(true)] out GlyphClassDef? glyphClass); internal abstract bool TryGetMarkAttachmentClass(ushort glyphId, [NotNullWhen(true)] out GlyphClassDef? markAttachmentClass); public abstract bool TryGetGlyphMetrics(CodePoint codePoint, TextAttributes textAttributes, TextDecorations textDecorations, LayoutMode layoutMode, ColorFontSupport support, [NotNullWhen(true)] out IReadOnlyList<GlyphMetrics>? metrics); public abstract IReadOnlyList<CodePoint> GetAvailableCodePoints(); internal abstract IReadOnlyList<GlyphMetrics> GetGlyphMetrics(CodePoint codePoint, ushort glyphId, TextAttributes textAttributes, TextDecorations textDecorations, LayoutMode layoutMode, ColorFontSupport support); internal abstract bool TryGetGSubTable([NotNullWhen(true)] out GSubTable? gSubTable); internal abstract void ApplySubstitution(GlyphSubstitutionCollection collection); internal abstract bool TryGetKerningOffset(ushort currentId, ushort nextId, out Vector2 vector); internal abstract void UpdatePositions(GlyphPositioningCollection collection); } internal sealed class FontReader : IDisposable { private readonly Stream stream; private readonly Dictionary<Type, Table> loadedTables = new Dictionary<Type, Table>(); private readonly TableLoader loader; private readonly bool isOwnedStream; private bool isDisposed; public TableFormat TableFormat { get; } public IReadOnlyDictionary<string, TableHeader> Headers { get; } public bool CompressedTableData { get; } public OutlineType OutlineType { get; } internal FontReader(Stream stream, TableLoader loader) { this.loader = loader; Func<BigEndianBinaryReader, TableHeader> func = TableHeader.Read; this.stream = stream; using BigEndianBinaryReader bigEndianBinaryReader = new BigEndianBinaryReader(stream, leaveOpen: true); uint num = bigEndianBinaryReader.ReadUInt32(); ushort num2; switch (num) { case 2001684038u: { TableFormat = TableFormat.Woff; uint num4 = bigEndianBinaryReader.ReadUInt32(); OutlineType = (OutlineType)num4; bigEndianBinaryReader.ReadUInt32(); num2 = bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); CompressedTableData = true; func = WoffTableHeader.Read; break; } case 2001684018u: { TableFormat = TableFormat.Woff2; uint num3 = bigEndianBinaryReader.ReadUInt32(); OutlineType = (OutlineType)num3; bigEndianBinaryReader.ReadUInt32(); num2 = bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt32(); uint count = bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); bigEndianBinaryReader.ReadUInt32(); CompressedTableData = true; Headers = Woff2Utils.ReadWoff2Headers(bigEndianBinaryReader, num2); isOwnedStream = true; byte[] buffer = bigEndianBinaryReader.ReadBytes((int)count); MemoryStream memoryStream = new MemoryStream(); using MemoryStream memoryStream2 = new MemoryStream(buffer); using BrotliStream brotliStream = new BrotliStream(memoryStream2, CompressionMode.Decompress); brotliStream.CopyTo(memoryStream); memoryStream.Position = 0L; this.stream = memoryStream; return; } default: TableFormat = TableFormat.Otf; OutlineType = (OutlineType)num; num2 = bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); bigEndianBinaryReader.ReadUInt16(); CompressedTableData = false; break; } Dictionary<string, TableHeader> dictionary = new Dictionary<string, TableHeader>(num2); for (int i = 0; i < num2; i++) { TableHeader tableHeader = func(bigEndianBinaryReader); dictionary[tableHeader.Tag] = tableHeader; } Headers = new ReadOnlyDictionary<string, TableHeader>(dictionary); } public FontReader(Stream stream) : this(stream, TableLoader.Default) { } public TTableType? TryGetTable<TTableType>() where TTableType : Table { if (loadedTables.TryGetValue(typeof(TTableType), out Table value)) { return (TTableType)value; } TTableType val = loader.Load<TTableType>(this); if (val == null) { return null; } value = val; loadedTables.Add(typeof(TTableType), val); return (TTableType)value; } public TTableType GetTable<TTableType>() where TTableType : Table { TTableType? val = TryGetTable<TTableType>(); if (val == null) { string tag = loader.GetTag<TTableType>(); throw new MissingFontTableException("Table '" + tag + "' is missing", tag); } return val; } public TableHeader? GetHeader(string tag) { if (!Headers.TryGetValue(tag, out TableHeader value)) { return null; } return value; } public BigEndianBinaryReader GetReaderAtTablePosition(string tableName) { if (!TryGetReaderAtTablePosition(tableName, out BigEndianBinaryReader reader)) { throw new InvalidFontTableException("Unable to find table " + tableName, tableName); } return reader; } public bool TryGetReaderAtTablePosition(string tableName, [NotNullWhen(true)] out BigEndianBinaryReader? reader) { TableHeader header; return TryGetReaderAtTablePosition(tableName, out reader, out header); } public bool TryGetReaderAtTablePosition(string tableName, [NotNullWhen(true)] out BigEndianBinaryReader? reader, [NotNullWhen(true)] out TableHeader? header) { header = GetHeader(tableName); if (header == null) { reader = null; return false; } reader = header?.CreateReader(stream); return reader != null; } public void Dispose() { if (!isDisposed && isOwnedStream) { stream.Dispose(); isDisposed = true; } } } public readonly struct FontRectangle : IEquatable<FontRectangle> { public static readonly FontRectangle Empty; public float X { get; } public float Y { get; } public float Width { get; } public float Height { get; } [EditorBrowsable(EditorBrowsableState.Never)] public Vector2 Location { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Vector2(X, Y); } } [EditorBrowsable(EditorBrowsableState.Never)] public Vector2 Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Vector2(Width, Height); } } [EditorBrowsable(EditorBrowsableState.Never)] public bool IsEmpty { get { if (!(Width <= 0f)) { return Height <= 0f; } return true; } } public float Top => Y; public float Right { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X + Width; } } public float Bottom { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Y + Height; } } public float Left => X; public FontRectangle(float x, float y, float width, float height) { X = x; Y = y; Width = width; Height = height; } public FontRectangle(Vector2 point, Vector2 size) : this(point.X, point.Y, size.X, size.Y) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(in FontRectangle left, in FontRectangle right) { return left.Equals(right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(in FontRectangle left, in FontRectangle right) { return !left.Equals(right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static FontRectangle FromLTRB(float left, float top, float right, float bottom) { return new FontRectangle(left, top, right - left, bottom - top); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Center(in FontRectangle rectangle) { return new Vector2(rectangle.Left + rectangle.Width / 2f, rectangle.Top + rectangle.Height / 2f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static FontRectangle Intersect(in FontRectangle a, in FontRectangle b) { float num = MathF.Max(a.X, b.X); float num2 = MathF.Min(a.Right, b.Right); float num3 = MathF.Max(a.Y, b.Y); float num4 = MathF.Min(a.Bottom, b.Bottom); if (num2 >= num && num4 >= num3) { return new FontRectangle(num, num3, num2 - num, num4 - num3); } return Empty; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static FontRectangle Inflate(in FontRectangle rectangle, float x, float y) { return rectangle.Inflate(x, y); } public static FontRectangle Transform(in FontRectangle rectangle, Matrix3x2 matrix) { Vector2 vector = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); Vector2 vector2 = Vector2.Transform(rectangle.Location, matrix); Vector2 size = vector - vector2; return new FontRectangle(vector2, size); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static FontRectangle Union(in FontRectangle a, in FontRectangle b) { float num = MathF.Min(a.X, b.X); float num2 = MathF.Max(a.Right, b.Right); float num3 = MathF.Min(a.Y, b.Y); float num4 = MathF.Max(a.Bottom, b.Bottom); return new FontRectangle(num, num3, num2 - num, num4 - num3); } public void Deconstruct(out float x, out float y, out float width, out float height) { x = X; y = Y; width = Width; height = Height; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FontRectangle Intersect(in FontRectangle rectangle) { return Intersect(in rectangle, in this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FontRectangle Inflate(float width, float height) { return new FontRectangle(X - width, Y - height, Width + 2f * width, Height + 2f * height); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FontRectangle Inflate(Vector2 size) { return Inflate(size.X, size.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(float x, float y) { if (X <= x && x < Right && Y <= y) { return y < Bottom; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(Vector2 point) { return Contains(point.X, point.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(in FontRectangle rectangle) { if (X <= rectangle.X && rectangle.Right <= Right && Y <= rectangle.Y) { return rectangle.Bottom <= Bottom; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IntersectsWith(in FontRectangle rectangle) { if (rectangle.X < Right && X < rectangle.Right && rectangle.Y < Bottom) { return Y < rectangle.Bottom; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FontRectangle Offset(Vector2 point) { return Offset(point.X, point.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FontRectangle Offset(float dx, float dy) { return new FontRectangle(X + dx, Y + dy, Width, Height); } public override int GetHashCode() { return HashCode.Combine(X, Y, Width, Height); } public override string ToString() { return $"FontRectangle [ X={X}, Y={Y}, Width={Width}, Height={Height} ]"; } public override bool Equals(object? obj) { if (obj is FontRectangle other) { return Equals(other); } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(FontRectangle other) { if (X.Equals(other.X) && Y.Equals(other.Y) && Width.Equals(other.Width)) { return Height.Equals(other.Height); } return false; } } [Flags] public enum FontStyle { Regular = 0, Bold = 1, Italic = 2, BoldItalic = 3 } public readonly struct Glyph { private readonly float pointSize; public GlyphMetrics GlyphMetrics { get; } internal Glyph(GlyphMetrics glyphMetrics, float pointSize) { GlyphMetrics = glyphMetrics; this.pointSize = pointSize; } public FontRectangle BoundingBox(GlyphLayoutMode mode, Vector2 location, float dpi) { return GlyphMetrics.GetBoundingBox(mode, location, pointSize * dpi); } internal void RenderTo(IGlyphRenderer surface, Vector2 location, Vector2 offset, GlyphLayoutMode mode, TextOptions options) { GlyphMetrics.RenderTo(surface, location, offset, mode, options); } } public readonly struct GlyphBounds { public CodePoint Codepoint { get; } public FontRectangle Bounds { get; } public int GraphemeIndex { get; } public int StringIndex { get; } public GlyphBounds(CodePoint codePoint, in FontRectangle bounds, int graphemeIndex, int stringIndex) { Codepoint = codePoint; Bounds = bounds; GraphemeIndex = graphemeIndex; StringIndex = stringIndex; } public override string ToString() { return $"Codepoint: {Codepoint}, Bounds: {Bounds}."; } } internal readonly struct GlyphLayout { public Glyph Glyph { get; } public CodePoint CodePoint { get; } public Vector2 BoxLocation { get; } public Vector2 PenLocation { get; } public Vector2 Offset { get; } public float AdvanceX { get; } public float AdvanceY { get; } public GlyphLayoutMode LayoutMode { get; } public bool IsStartOfLine { get; } public int GraphemeIndex { get; } public int StringIndex { get; } internal GlyphLayout(Glyph glyph, Vector2 boxLocation, Vector2 penLocation, Vector2 offset, float advanceWidth, float advanceHeight, GlyphLayoutMode layoutMode, bool isStartOfLine, int graphemeIndex, int stringIndex) { Glyph = glyph; CodePoint = glyph.GlyphMetrics.CodePoint; BoxLocation = boxLocation; PenLocation = penLocation; Offset = offset; Adva