Decompiled source of Fontifier v1.1.4

Mods/Fontifier.dll

Decompiled a week ago
using 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
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