using System; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Text; using Quik; namespace Quik.Media.Defaults { public static unsafe class FontConfig { private const string fontconfig = "fontconfig"; public static bool Exists { get; } public static IntPtr FAMILY { get; } = Marshal.StringToHGlobalAnsi("family"); public static IntPtr STYLE { get; } = Marshal.StringToHGlobalAnsi("style"); public static IntPtr FILE { get; } = Marshal.StringToHGlobalAnsi("file"); public static IntPtr WEIGHT { get; } = Marshal.StringToHGlobalAnsi("weight"); public static IntPtr SLANT { get; } = Marshal.StringToHGlobalAnsi("slant"); static FontConfig() { try { if (FcInitLoadConfigAndFonts() == null) { Exists = false; } Exists = true; } catch { Exists = false; } } [DllImport(fontconfig, EntryPoint = "FcInitLoadConfigAndFonts")] public static extern FcConfig* FcInitLoadConfigAndFonts(); [DllImport(fontconfig, EntryPoint = "FcConfigGetCurrent")] public static extern FcConfig ConfigGetCurrent(); [DllImport(fontconfig, EntryPoint = "FcPatternCreate")] public static extern FcPattern PatternCreate(); [DllImport(fontconfig, EntryPoint = "FcPatternCreate")] public static extern bool FcPatternAdd(FcPattern pattern, IntPtr what, FcValue value, bool append); [DllImport(fontconfig, EntryPoint = "FcObjectSetBuild", CallingConvention = CallingConvention.Cdecl)] public static extern FcObjectSet ObjectSetBuild(IntPtr i1, IntPtr i2, IntPtr i3, IntPtr i4, IntPtr i5, IntPtr i6); public static FcObjectSet ObjectSetBuild(IntPtr i1) { return ObjectSetBuild(i1, IntPtr.Zero); } public static FcObjectSet ObjectSetBuild(IntPtr i1, IntPtr i2) { return ObjectSetBuild(i1, i2, IntPtr.Zero); } public static FcObjectSet ObjectSetBuild(IntPtr i1, IntPtr i2, IntPtr i3) { return ObjectSetBuild(i1, i2, i3, IntPtr.Zero); } public static FcObjectSet ObjectSetBuild(IntPtr i1, IntPtr i2, IntPtr i3, IntPtr i4) { return ObjectSetBuild(i1, i2, i3, i4, IntPtr.Zero); } public static FcObjectSet ObjectSetBuild(IntPtr i1, IntPtr i2, IntPtr i3, IntPtr i4, IntPtr i5) { return ObjectSetBuild(i1, i2, i3, i4, i5, IntPtr.Zero); } [DllImport(fontconfig, EntryPoint = "FcFontList")] public static extern FcFontSet FontList(FcConfig config, FcPattern pattern, FcObjectSet objectSet); [DllImport(fontconfig, EntryPoint = "FcNameUnparse")] public static extern IntPtr NameUnparse(FcPattern pat); public static string NameUnparseStr(FcPattern pat) => Marshal.PtrToStringAnsi(NameUnparse(pat)); [DllImport(fontconfig, EntryPoint = "FcPatternGetString")] public static extern FcResult PatternGetString(FcPattern p, IntPtr what, int n, out IntPtr val); public static FcResult PatternGetString(FcPattern p, IntPtr what, out string str) { FcResult i = PatternGetString(p, what, 0, out IntPtr ptr); if (i == FcResult.Match) { str = Marshal.PtrToStringAnsi(ptr); } else { str = null; } Marshal.FreeHGlobal(ptr); return i; } [DllImport(fontconfig, EntryPoint = "FcPatternGet")] public static extern FcResult PatternGet(FcPattern p, IntPtr what, int id, out FcValue value); [DllImport(fontconfig, EntryPoint = "FcFontSetDestroy")] public static extern void FontSetDestroy(FcFontSet fs); [DllImport(fontconfig, EntryPoint = "FcObjectSetDestroy")] public static extern void ObjectSetDestroy (FcObjectSet os); [DllImport(fontconfig, EntryPoint = "FcConfigDestroy")] public static extern void ConfigDestroy (FcConfig cfg); [DllImport(fontconfig, EntryPoint = "FcPatternDestroy")] public static extern void PatternDestroy (FcPattern os); #region Range [DllImport(fontconfig, EntryPoint = "FcRangeCreateDouble")] public static extern IntPtr RangeCreateDouble(double begin, double end); [DllImport(fontconfig, EntryPoint = "FcRangeCreateInteger")] public static extern IntPtr RangeCreateInteger (int begin, int end); [DllImport(fontconfig, EntryPoint = "FcRangeDestroy")] public static extern void RangeDestroy(IntPtr range); [DllImport(fontconfig, EntryPoint = "FcRangeCopy")] public static extern IntPtr RangeCopy (IntPtr range); [DllImport(fontconfig, EntryPoint = "FcRangeGetDouble")] public static extern bool RangeGetDouble(IntPtr range, out double start, out double end); #endregion } public enum FcResult { Match, NoMatch, TypeMismatch, NoId, OutOfMemory } public struct FcConfig { public readonly IntPtr Handle; } public struct FcPattern { public readonly IntPtr Handle; } public unsafe struct FcObjectSet { public readonly IntPtr Handle; private Accessor* AsPtr => (Accessor*)Handle; public int NObject => AsPtr->nobject; public int SObject => AsPtr->sobject; #pragma warning disable CS0649 // Will always have default value. private struct Accessor { public int nobject; public int sobject; public byte** objects; } #pragma warning restore CS0649 } public unsafe struct FcFontSet { public readonly IntPtr Handle; private Accessor* AsPtr => (Accessor*)Handle; public int NFont => AsPtr->nfont; public int SFont => AsPtr->sfont; public FcPattern this[int i] { get { if (i < 0 || i >= NFont) throw new IndexOutOfRangeException(); return AsPtr->fonts[i]; } } #pragma warning disable CS0649 // Will always have default value. private struct Accessor { public int nfont; public int sfont; public FcPattern* fonts; } #pragma warning restore CS0649 } public enum FcType { Unknown = -1, Void, Integer, Double, String, Bool, Matrix, CharSet, FTFace, LangSet, Range } [StructLayout(LayoutKind.Explicit)] public readonly struct FcValue { [FieldOffset(0)] public readonly FcType Type; [FieldOffset(sizeof(FcType))] public readonly IntPtr Pointer; [FieldOffset(sizeof(FcType))] public readonly int Int; [FieldOffset(sizeof(FcType))] public readonly double Double; } }