Browse Source

Finished skia support

Benedikt Schroeder 7 năm trước cách đây
mục cha
commit
5fe6276228

+ 1 - 1
samples/ControlCatalog.Desktop/Program.cs

@@ -23,7 +23,7 @@ namespace ControlCatalog
         /// This method is needed for IDE previewer infrastructure
         /// </summary>
         public static AppBuilder BuildAvaloniaApp()
-            => AppBuilder.Configure<App>().LogToDebug().UsePlatformDetect();
+            => AppBuilder.Configure<App>().LogToDebug().UsePlatformDetect().UseSkia();
 
         private static void ConfigureAssetAssembly(AppBuilder builder)
         {

+ 1 - 289
src/Avalonia.Visuals/Media/FontFamily.cs

@@ -2,12 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using Avalonia.Platform;
+using Avalonia.Media.Fonts;
 
 namespace Avalonia.Media
 {
@@ -37,287 +32,4 @@ namespace Avalonia.Media
             return Name;
         }
     }
-
-    public class FontFamilyKey
-    {
-        public FontFamilyKey(Uri source)
-        {
-            if (source.AbsolutePath.Contains(".ttf"))
-            {
-                if (source.Scheme == "res")
-                {
-                    FileName = source.AbsolutePath.Split('/').Last();
-                }
-                else
-                {
-                    var filePathWithoutExtension = source.AbsolutePath.Replace(".ttf", "");
-                    var fileNameWithoutExtension = filePathWithoutExtension.Split('.').Last();
-                    FileName = fileNameWithoutExtension + ".ttf";
-                }
-
-                Location = new Uri(source.OriginalString.Replace("." + FileName, ""), UriKind.RelativeOrAbsolute);
-            }
-            else
-            {
-                Location = source;
-            }
-        }
-
-        public Uri Location { get; }
-
-        public string FileName { get; }
-
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                var hash = (int)2166136261;
-
-                if (Location != null)
-                {
-                    hash = (hash * 16777619) ^ Location.GetHashCode();
-                }
-
-                if (FileName != null)
-                {
-                    hash = (hash * 16777619) ^ FileName.GetHashCode();
-                }
-
-                return hash;
-            }
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (!(obj is FontFamilyKey other)) return false;
-
-            if (Location != other.Location) return false;
-
-            if (FileName != other.FileName) return false;
-
-            return true;
-        }
-
-        public override string ToString()
-        {
-            if (FileName != null)
-            {
-                if (Location.Scheme == "resm")
-                {
-                    return Location + "." + FileName;
-                }
-
-                return Location + "/" + FileName;
-            }
-
-            return Location.ToString();
-        }
-    }
-
-    public class FontResource
-    {
-        public FontResource(Uri source)
-        {
-            Source = source;
-        }
-
-        public Uri Source { get; }
-    }
-
-    public class FontResourceCollection
-    {
-        private Dictionary<Uri, FontResource> _fontResources;
-        private readonly IFontResourceLoader _fontResourceLoader = new FontResourceLoader();
-
-        public FontResourceCollection(FontFamilyKey key)
-        {
-            Key = key;
-        }
-
-        public FontFamilyKey Key { get; }
-
-        public IEnumerable<FontResource> FontResources
-        {
-            get
-            {
-                if (_fontResources == null)
-                {
-                    _fontResources = CreateFontResources();
-                }
-
-                return _fontResources.Values;
-            }
-        }
-
-        private Dictionary<Uri, FontResource> CreateFontResources()
-        {
-            return _fontResourceLoader.GetFontResources(Key).ToDictionary(x => x.Source);
-        }
-    }
-
-    public interface IFontResourceLoader
-    {
-        IEnumerable<FontResource> GetFontResources(FontFamilyKey fontFamilyKey);
-    }
-
-    public class FontResourceLoader : IFontResourceLoader
-    {
-        private static readonly Dictionary<string, AssemblyDescriptor> s_assemblyNameCache
-            = new Dictionary<string, AssemblyDescriptor>();
-
-        private readonly AssemblyDescriptor _defaultAssembly;
-
-        public FontResourceLoader(Assembly assembly = null)
-        {
-            if (assembly == null)
-            {
-                assembly = Assembly.GetEntryAssembly();
-            }
-            if (assembly != null)
-            {
-                _defaultAssembly = new AssemblyDescriptor(assembly);
-            }
-        }
-
-        public IEnumerable<FontResource> GetFontResources(FontFamilyKey fontFamilyKey)
-        {
-            return fontFamilyKey.FileName != null
-                ? GetFontResourcesByFileName(fontFamilyKey.Location, fontFamilyKey.FileName)
-                : GetFontResourcesByLocation(fontFamilyKey.Location);
-        }
-
-        private IEnumerable<FontResource> GetFontResourcesByLocation(Uri location)
-        {
-            var assembly = GetAssembly(location);
-
-            var locationPath = GetLocationPath(location);
-
-            var matchingResources = assembly.Resources.Where(x => x.Contains(locationPath));
-
-            return matchingResources.Select(x => new FontResource(GetResourceUri(x, assembly.Name)));
-        }
-
-        private IEnumerable<FontResource> GetFontResourcesByFileName(Uri location, string fileName)
-        {
-            var assembly = GetAssembly(location);
-
-            var compareTo = GetLocationPath(location) + fileName.Split('*').First();
-
-            var matchingResources = assembly.Resources.Where(x => x.Contains(compareTo));
-
-            return matchingResources.Select(x => new FontResource(GetResourceUri(x, assembly.Name)));
-        }
-
-        private static Uri GetResourceUri(string path, string assemblyName)
-        {
-            return new Uri("resm:" + path + "?assembly=" + assemblyName);
-        }
-
-        private static string GetLocationPath(Uri uri)
-        {
-            if (uri.Scheme == "resm") return uri.AbsolutePath;
-
-            var path = uri.AbsolutePath.Replace("/", ".");
-
-            return path;
-        }
-
-        private AssemblyDescriptor GetAssembly(Uri uri)
-        {
-            if (uri == null) return null;
-
-            var parameters = ParseParameters(uri);
-
-            return parameters.TryGetValue("assembly", out var assemblyName) ? GetAssembly(assemblyName) : null;
-        }
-
-        private AssemblyDescriptor GetAssembly(string name)
-        {
-            if (name == null)
-            {
-                return _defaultAssembly;
-            }
-
-            if (!s_assemblyNameCache.TryGetValue(name, out var rv))
-            {
-                var loadedAssemblies = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies();
-                var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name);
-                if (match != null)
-                {
-                    s_assemblyNameCache[name] = rv = new AssemblyDescriptor(match);
-                }
-                else
-                {
-                    // iOS does not support loading assemblies dynamically!
-                    //
-#if NETCOREAPP1_0
-                    s_assemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
-#elif __IOS__
-                    throw new InvalidOperationException(
-                        $"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
-#else
-                    s_assemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name));
-#endif
-                }
-            }
-
-            return rv;
-        }
-
-        private static Dictionary<string, string> ParseParameters(Uri uri)
-        {
-            return uri.Query.TrimStart('?')
-                .Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries)
-                .Select(p => p.Split('='))
-                .ToDictionary(p => p[0], p => p[1]);
-        }
-
-        private class AssemblyDescriptor
-        {
-            public AssemblyDescriptor(Assembly assembly)
-            {
-                Assembly = assembly;
-
-                if (Assembly == null) return;
-
-                Resources = assembly.GetManifestResourceNames().ToList();
-
-                Name = Assembly.GetName().Name;
-            }
-
-            public string Name { get; }
-            public Assembly Assembly { get; }
-            public List<string> Resources { get; }
-        }
-    }
-
-    public class CachedFontFamily
-    {
-        private readonly FontResourceCollection _fontResourceCollection;
-
-        public CachedFontFamily(FontFamilyKey key, FontResourceCollection fontResourceCollection)
-        {
-            Key = key;
-            _fontResourceCollection = fontResourceCollection;
-        }
-
-        public FontFamilyKey Key { get; }
-
-        public IEnumerable<FontResource> FontResources => _fontResourceCollection.FontResources;
-    }
-
-    public class FontFamilyCache
-    {
-        private static readonly ConcurrentDictionary<FontFamilyKey, CachedFontFamily> s_cachedFontFamilies = new ConcurrentDictionary<FontFamilyKey, CachedFontFamily>();
-
-        public CachedFontFamily GetOrAddFontFamily(FontFamilyKey key)
-        {
-            return s_cachedFontFamilies.GetOrAdd(key, CreateCachedFontFamily);
-        }
-
-        private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey)
-        {
-            return new CachedFontFamily(fontFamilyKey, new FontResourceCollection(fontFamilyKey));
-        }
-    }
 }

+ 22 - 0
src/Avalonia.Visuals/Media/Fonts/CachedFontFamily.cs

@@ -0,0 +1,22 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System.Collections.Generic;
+
+namespace Avalonia.Media.Fonts
+{
+    public class CachedFontFamily
+    {
+        private readonly FontResourceCollection _fontResourceCollection;
+
+        public CachedFontFamily(FontFamilyKey key, FontResourceCollection fontResourceCollection)
+        {
+            Key = key;
+            _fontResourceCollection = fontResourceCollection;
+        }
+
+        public FontFamilyKey Key { get; }
+
+        public IEnumerable<FontResource> FontResources => _fontResourceCollection.FontResources;
+    }
+}

+ 22 - 0
src/Avalonia.Visuals/Media/Fonts/FontFamilyCache.cs

@@ -0,0 +1,22 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System.Collections.Concurrent;
+
+namespace Avalonia.Media.Fonts
+{
+    public static class FontFamilyCache
+    {
+        private static readonly ConcurrentDictionary<FontFamilyKey, CachedFontFamily> s_cachedFontFamilies = new ConcurrentDictionary<FontFamilyKey, CachedFontFamily>();
+
+        public static CachedFontFamily GetOrAddFontFamily(FontFamilyKey key)
+        {
+            return s_cachedFontFamilies.GetOrAdd(key, CreateCachedFontFamily);
+        }
+
+        private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey)
+        {
+            return new CachedFontFamily(fontFamilyKey, new FontResourceCollection(fontFamilyKey));
+        }
+    }
+}

+ 84 - 0
src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs

@@ -0,0 +1,84 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Linq;
+
+namespace Avalonia.Media.Fonts
+{
+    public class FontFamilyKey
+    {
+        public FontFamilyKey(Uri source)
+        {
+            if (source.AbsolutePath.Contains(".ttf"))
+            {
+                if (source.Scheme == "res")
+                {
+                    FileName = source.AbsolutePath.Split('/').Last();
+                    Location = new Uri(source.OriginalString.Replace("/" + FileName, ""), UriKind.RelativeOrAbsolute);
+                }
+                else
+                {
+                    var filePathWithoutExtension = source.AbsolutePath.Replace(".ttf", "");
+                    var fileNameWithoutExtension = filePathWithoutExtension.Split('.').Last();
+                    FileName = fileNameWithoutExtension + ".ttf";
+                    Location = new Uri(source.OriginalString.Replace("." + FileName, ""), UriKind.RelativeOrAbsolute);
+                }            
+            }
+            else
+            {
+                Location = source;
+            }
+        }
+
+        public Uri Location { get; }
+
+        public string FileName { get; }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                var hash = (int)2166136261;
+
+                if (Location != null)
+                {
+                    hash = (hash * 16777619) ^ Location.GetHashCode();
+                }
+
+                if (FileName != null)
+                {
+                    hash = (hash * 16777619) ^ FileName.GetHashCode();
+                }
+
+                return hash;
+            }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is FontFamilyKey other)) return false;
+
+            if (Location != other.Location) return false;
+
+            if (FileName != other.FileName) return false;
+
+            return true;
+        }
+
+        public override string ToString()
+        {
+            if (FileName != null)
+            {
+                if (Location.Scheme == "resm")
+                {
+                    return Location.AbsolutePath + "." + FileName;
+                }
+
+                return Location.AbsolutePath + "/" + FileName;
+            }
+
+            return Location.AbsolutePath;
+        }
+    }
+}

+ 17 - 0
src/Avalonia.Visuals/Media/Fonts/FontResource.cs

@@ -0,0 +1,17 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+
+namespace Avalonia.Media.Fonts
+{
+    public class FontResource
+    {
+        public FontResource(Uri source)
+        {
+            Source = source;
+        }
+
+        public Uri Source { get; }
+    }
+}

+ 40 - 0
src/Avalonia.Visuals/Media/Fonts/FontResourceCollection.cs

@@ -0,0 +1,40 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Avalonia.Media.Fonts
+{
+    public class FontResourceCollection
+    {
+        private Dictionary<Uri, FontResource> _fontResources;
+        private readonly IFontResourceLoader _fontResourceLoader = new FontResourceLoader();
+
+        public FontResourceCollection(FontFamilyKey key)
+        {
+            Key = key;
+        }
+
+        public FontFamilyKey Key { get; }
+
+        public IEnumerable<FontResource> FontResources
+        {
+            get
+            {
+                if (_fontResources == null)
+                {
+                    _fontResources = CreateFontResources();
+                }
+
+                return _fontResources.Values;
+            }
+        }
+
+        private Dictionary<Uri, FontResource> CreateFontResources()
+        {
+            return _fontResourceLoader.GetFontResources(Key).ToDictionary(x => x.Source);
+        }
+    }
+}

+ 142 - 0
src/Avalonia.Visuals/Media/Fonts/FontResourceLoader.cs

@@ -0,0 +1,142 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Avalonia.Platform;
+
+namespace Avalonia.Media.Fonts
+{
+    public class FontResourceLoader : IFontResourceLoader
+    {
+        private static readonly Dictionary<string, AssemblyDescriptor> s_assemblyNameCache
+            = new Dictionary<string, AssemblyDescriptor>();
+
+        private readonly AssemblyDescriptor _defaultAssembly;
+
+        public FontResourceLoader(Assembly assembly = null)
+        {
+            if (assembly == null)
+            {
+                assembly = Assembly.GetEntryAssembly();
+            }
+            if (assembly != null)
+            {
+                _defaultAssembly = new AssemblyDescriptor(assembly);
+            }
+        }
+
+        public IEnumerable<FontResource> GetFontResources(FontFamilyKey fontFamilyKey)
+        {
+            return fontFamilyKey.FileName != null
+                ? GetFontResourcesByFileName(fontFamilyKey.Location, fontFamilyKey.FileName)
+                : GetFontResourcesByLocation(fontFamilyKey.Location);
+        }
+
+        private IEnumerable<FontResource> GetFontResourcesByLocation(Uri location)
+        {
+            var assembly = GetAssembly(location);
+
+            var locationPath = GetLocationPath(location);
+
+            var matchingResources = assembly.Resources.Where(x => x.Contains(locationPath));
+
+            return matchingResources.Select(x => new FontResource(GetResourceUri(x, assembly.Name)));
+        }
+
+        private IEnumerable<FontResource> GetFontResourcesByFileName(Uri location, string fileName)
+        {
+            var assembly = GetAssembly(location);
+
+            var compareTo = GetLocationPath(location) + "." + fileName.Split('*').First();
+
+            var matchingResources = assembly.Resources.Where(x => x.Contains(compareTo));
+
+            return matchingResources.Select(x => new FontResource(GetResourceUri(x, assembly.Name)));
+        }
+
+        private static Uri GetResourceUri(string path, string assemblyName)
+        {
+            return new Uri("resm:" + path + "?assembly=" + assemblyName);
+        }
+
+        private static string GetLocationPath(Uri uri)
+        {
+            if (uri.Scheme == "resm") return uri.AbsolutePath;
+
+            var path = uri.AbsolutePath.Replace("/", ".");
+
+            return path;
+        }
+
+        private AssemblyDescriptor GetAssembly(Uri uri)
+        {
+            if (uri == null) return null;
+
+            var parameters = ParseParameters(uri);
+
+            return parameters.TryGetValue("assembly", out var assemblyName) ? GetAssembly(assemblyName) : null;
+        }
+
+        private AssemblyDescriptor GetAssembly(string name)
+        {
+            if (name == null)
+            {
+                return _defaultAssembly;
+            }
+
+            if (!s_assemblyNameCache.TryGetValue(name, out var rv))
+            {
+                var loadedAssemblies = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies();
+                var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name);
+                if (match != null)
+                {
+                    s_assemblyNameCache[name] = rv = new AssemblyDescriptor(match);
+                }
+                else
+                {
+                    // iOS does not support loading assemblies dynamically!
+                    //
+#if NETCOREAPP1_0
+                    s_assemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
+#elif __IOS__
+                    throw new InvalidOperationException(
+                        $"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
+#else
+                    s_assemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name));
+#endif
+                }
+            }
+
+            return rv;
+        }
+
+        private static Dictionary<string, string> ParseParameters(Uri uri)
+        {
+            return uri.Query.TrimStart('?')
+                .Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries)
+                .Select(p => p.Split('='))
+                .ToDictionary(p => p[0], p => p[1]);
+        }
+
+        private class AssemblyDescriptor
+        {
+            public AssemblyDescriptor(Assembly assembly)
+            {
+                Assembly = assembly;
+
+                if (Assembly == null) return;
+
+                Resources = assembly.GetManifestResourceNames().ToList();
+
+                Name = Assembly.GetName().Name;
+            }
+
+            public string Name { get; }
+            public Assembly Assembly { get; }
+            public List<string> Resources { get; }
+        }
+    }
+}

+ 12 - 0
src/Avalonia.Visuals/Media/Fonts/IFontResourceLoader.cs

@@ -0,0 +1,12 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System.Collections.Generic;
+
+namespace Avalonia.Media.Fonts
+{
+    public interface IFontResourceLoader
+    {
+        IEnumerable<FontResource> GetFontResources(FontFamilyKey fontFamilyKey);
+    }
+}

+ 32 - 11
src/Skia/Avalonia.Skia/TypefaceCache.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 using Avalonia.Media;
+using Avalonia.Media.Fonts;
 using Avalonia.Platform;
 using SkiaSharp;
 
@@ -47,7 +48,7 @@ namespace Avalonia.Skia
 
         unsafe static SKTypeface GetTypeface(FontFamily fontFamily, FontKey key)
         {
-            var familyKey = fontFamily.Key.ToString();
+            var familyKey = fontFamily.Name;
 
             if (!Cache.TryGetValue(familyKey, out var entry))
             {
@@ -56,21 +57,41 @@ namespace Avalonia.Skia
 
             if (!entry.TryGetValue(key, out var typeface))
             {
-                //if (fontFamily.BaseUri != null)
-                //{
-                //    var stream = AvaloniaLocator.Current.GetService<IAssetLoader>().Open(fontFamily.BaseUri);
+                if (fontFamily.Key != null)
+                {
+                    var cachedFontFamily = FontFamilyCache.GetOrAddFontFamily(fontFamily.Key);
 
-                //    typeface = SKTypeface.FromStream(stream);
-                //}
-                //else
-                //{
-                    typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant);
+                    var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+                    foreach (var fontResource in cachedFontFamily.FontResources)
+                    {
+                        var stream = assetLoader.Open(fontResource.Source);
+
+                        typeface = SKTypeface.FromStream(stream);
+
+                        if (typeface.FamilyName != familyKey) continue;
+
+                        var fontKey = new FontKey((SKFontStyleWeight)typeface.FontWeight, typeface.FontSlant);
+
+                        entry[fontKey] = typeface;
+                    }
+
+                    entry.TryGetValue(key, out typeface);
 
                     if (typeface == null)
                     {
-                        typeface = SKTypeface.FromFamilyName(null, SKTypefaceStyle.Normal);
+                        typeface = SKTypeface.FromFamilyName(null);
                     }
-                //}
+
+                    return typeface;
+                }
+
+                typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant);
+
+                if (typeface == null)
+                {
+                    typeface = SKTypeface.FromFamilyName(null);
+                }
 
                 entry[key] = typeface;
             }

+ 9 - 9
src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs

@@ -8,6 +8,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using Avalonia.Media;
+using Avalonia.Media.Fonts;
 using Avalonia.Platform;
 using SharpDX;
 using DWrite = SharpDX.DirectWrite;
@@ -26,17 +27,13 @@ namespace Avalonia.Direct2D1.Media
         {
             Text = text;
 
-            var factory = AvaloniaLocator.Current.GetService<DWrite.Factory>();          
+            var factory = AvaloniaLocator.Current.GetService<DWrite.Factory>();
 
             DWrite.TextFormat textFormat;
 
             if (typeface.FontFamily.Key != null)
             {
-                var fontFamilyCache = new FontFamilyCache();
-
-                var fontFamily = fontFamilyCache.GetOrAddFontFamily(typeface.FontFamily.Key);
-
-                var fontCollection = Direct2D1CustomFontCollectionCache.GetOrAddCustomFontCollection(fontFamily, factory);
+                var fontCollection = Direct2D1CustomFontCollectionCache.GetOrAddCustomFontCollection(typeface.FontFamily.Key, factory);
 
                 textFormat = new DWrite.TextFormat(
                         factory,
@@ -54,6 +51,7 @@ namespace Avalonia.Direct2D1.Media
                     typeface.FontFamily.Name,
                     (DWrite.FontWeight)typeface.Weight,
                     (DWrite.FontStyle)typeface.Style,
+                    DWrite.FontStretch.Normal,
                     (float)typeface.FontSize);
             }
 
@@ -154,13 +152,15 @@ namespace Avalonia.Direct2D1.Media
         private static readonly ConcurrentDictionary<FontFamilyKey, DWrite.FontCollection> s_cachedFonts =
             new ConcurrentDictionary<FontFamilyKey, DWrite.FontCollection>();
 
-        public static DWrite.FontCollection GetOrAddCustomFontCollection(CachedFontFamily fontFamily, DWrite.Factory factory)
+        public static DWrite.FontCollection GetOrAddCustomFontCollection(FontFamilyKey key, DWrite.Factory factory)
         {
-            return s_cachedFonts.GetOrAdd(fontFamily.Key, x => CreateCustomFontCollection(fontFamily, factory));
+            return s_cachedFonts.GetOrAdd(key, x => CreateCustomFontCollection(key, factory));
         }
 
-        private static DWrite.FontCollection CreateCustomFontCollection(CachedFontFamily fontFamily, DWrite.Factory factory)
+        private static DWrite.FontCollection CreateCustomFontCollection(FontFamilyKey key, DWrite.Factory factory)
         {
+            var fontFamily = FontFamilyCache.GetOrAddFontFamily(key);
+
             var fontLoader = new ResourceFontLoader(factory, fontFamily.FontResources);
 
             return new DWrite.FontCollection(factory, fontLoader, fontLoader.Key);