Benedikt Schroeder 7 年之前
父節點
當前提交
9f29e9a8f4

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

@@ -3,6 +3,7 @@ using System.Linq;
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Logging.Serilog;
+using Avalonia.Media;
 using Avalonia.Platform;
 using Serilog;
 
@@ -15,6 +16,7 @@ namespace ControlCatalog
         {
             // TODO: Make this work with GTK/Skia/Cairo depending on command-line args
             // again.
+            AvaloniaLocator.CurrentMutable.Bind<IFontFamilyCache>().ToConstant(new FontFamilyCache());
             BuildAvaloniaApp().Start<MainWindow>();
         }
 
@@ -28,7 +30,7 @@ namespace ControlCatalog
         {
             AvaloniaLocator.CurrentMutable
                 .GetService<IAssetLoader>()
-                .SetDefaultAssembly(typeof(App).Assembly);
+                .SetDefaultAssembly(typeof(App).Assembly);           
         }
     }
 }

+ 103 - 34
src/Avalonia.Visuals/Media/FontFamily.cs

@@ -2,15 +2,15 @@
 // 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.Collections.ObjectModel;
+using System.Linq;
 
 namespace Avalonia.Media
 {
     public class FontFamily
     {
-        private IFontFamily _loadedFamily;
-
         public FontFamily(string familyName) : this(familyName, null) { }
 
         public FontFamily(string familyName, Uri baseUri)
@@ -25,30 +25,20 @@ namespace Avalonia.Media
         public Uri BaseUri => FontFamilyKey.BaseUri;
 
         internal FontFamilyKey FontFamilyKey { get; }
-
-        internal IFontFamily LoadedFamily => _loadedFamily ?? (_loadedFamily = AvaloniaLocator.Current
-                                                 .GetService<IFontFamilyLoader>()
-                                                 .LoadFontFamily(FontFamilyKey));
-
-        public IEnumerable<FamilyTypeface> AvailableTypefaces => LoadedFamily.SupportedTypefaces;
     }
 
     public class FamilyTypeface
     {
-        public FamilyTypeface()
-        {
-            FontStyle = FontStyle.Normal;
-            FontWeight = FontWeight.Normal;
-        }
-
-        public FamilyTypeface(Typeface typeface)
+        public FamilyTypeface(Uri resourceUri = null, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal)
         {
-            FontStyle = typeface.Style;
-            FontWeight = typeface.Weight;
+            ResourceUri = resourceUri;
+            FontStyle = fontStyle;
+            FontWeight = fontWeight;
         }
 
-        public FontStyle FontStyle { get; }
+        public Uri ResourceUri { get; }
         public FontWeight FontWeight { get; }
+        public FontStyle FontStyle { get; }
     }
 
     public class FontFamilyKey
@@ -64,39 +54,118 @@ namespace Avalonia.Media
         public string FriendlyName { get; }
 
         public Uri BaseUri { get; }
-    }
 
-    internal interface IFontFamily
-    {
-        IEnumerable<FamilyTypeface> SupportedTypefaces { get; }
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                var hash = (int)2166136261;
+
+                if (FriendlyName != null)
+                {
+                    hash = (hash * 16777619) ^ FriendlyName.GetHashCode();
+                }
+
+                if (BaseUri != null)
+                {
+                    hash = (hash * 16777619) ^ BaseUri.GetHashCode();
+                }
+
+                return hash;
+            }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is FontFamilyKey other)) return false;
+
+            if (FriendlyName != other.FriendlyName) return false;
+
+            if (BaseUri != other.BaseUri) return false;
+
+            return true;
+        }
     }
 
-    internal class SystemFont : IFontFamily
+    public class FamilyTypefaceKey
     {
-        public SystemFont() : this(new List<FamilyTypeface> { new FamilyTypeface() }) { }
+        public FamilyTypefaceKey(FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal)
+        {
+            FontWeight = fontWeight;
+            FontStyle = fontStyle;
+        }
+
+        public FontWeight FontWeight { get; }
+
+        public FontStyle FontStyle { get; }
 
-        public SystemFont(IEnumerable<FamilyTypeface> supportedTypefaces)
+        public override int GetHashCode()
         {
-            SupportedTypefaces = new ReadOnlyCollection<FamilyTypeface>(new List<FamilyTypeface>(supportedTypefaces));
+            unchecked
+            {
+                var hash = (int)2166136261;
+
+                hash = (hash * 16777619) ^ FontWeight.GetHashCode();
+
+                hash = (hash * 16777619) ^ FontStyle.GetHashCode();
+
+                return hash;
+            }
         }
 
-        public IEnumerable<FamilyTypeface> SupportedTypefaces { get; }
+        public override bool Equals(object obj)
+        {
+            if (!(obj is FamilyTypefaceKey other)) return false;
+
+            if (FontWeight != other.FontWeight) return false;
+
+            if (FontStyle != other.FontStyle) return false;
+
+            return true;
+        }
     }
 
-    internal class CustomFont : IFontFamily
+    public class CachedFontFamily
     {
-        public CustomFont() : this(new List<FamilyTypeface> { new FamilyTypeface() }) { }
+        private readonly ConcurrentDictionary<FamilyTypefaceKey, FamilyTypeface> _typefaces =
+            new ConcurrentDictionary<FamilyTypefaceKey, FamilyTypeface>();
+
+        public IEnumerable<FamilyTypeface> SupportedTypefaces => _typefaces.Values;
+
+        public bool TryGetFamilyTypeface(out FamilyTypeface typeface, FontWeight fontWeight = FontWeight.Normal,
+            FontStyle fontStyle = FontStyle.Normal)
+        {
+            return _typefaces.TryGetValue(new FamilyTypefaceKey(fontWeight, fontStyle), out typeface);
+        }
 
-        public CustomFont(IEnumerable<FamilyTypeface> supportedTypefaces)
+        public FamilyTypeface GetOrAddFamilyTypeface(Uri resourceUri, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal)
         {
-            SupportedTypefaces = new ReadOnlyCollection<FamilyTypeface>(new List<FamilyTypeface>(supportedTypefaces));
+            return _typefaces.GetOrAdd(new FamilyTypefaceKey(fontWeight, fontStyle), x => CreateFamilyTypeface(x, resourceUri));
         }
 
-        public IEnumerable<FamilyTypeface> SupportedTypefaces { get; }
+        private static FamilyTypeface CreateFamilyTypeface(FamilyTypefaceKey familyTypefaceKey, Uri resourceUri)
+        {
+            return new FamilyTypeface(resourceUri, familyTypefaceKey.FontWeight, familyTypefaceKey.FontStyle);
+        }
+    }
+
+    public interface IFontFamilyCache
+    {
+        CachedFontFamily GetOrAddFontFamily(FontFamily fontFamily);
     }
 
-    internal interface IFontFamilyLoader
+    public class FontFamilyCache : IFontFamilyCache
     {
-        IFontFamily LoadFontFamily(FontFamilyKey fontFamilyKey);
+        private readonly ConcurrentDictionary<FontFamilyKey, CachedFontFamily> _cachedFontFamilies = new ConcurrentDictionary<FontFamilyKey, CachedFontFamily>();
+
+        public CachedFontFamily GetOrAddFontFamily(FontFamily fontFamily)
+        {
+            return _cachedFontFamilies.GetOrAdd(fontFamily.FontFamilyKey, CreateCachedFontFamily);
+        }
+
+        private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey)
+        {
+            return new CachedFontFamily();
+        }
     }
 }

+ 36 - 2
src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs

@@ -20,21 +20,55 @@ namespace Avalonia.Markup.Xaml.Converters
 
             var fontFamilyExpression = s.Split('#');
 
+            string familyName;
+
+            Uri baseUri = null;
+
+            var fontWeight = FontWeight.Normal;
+
+            var fontStyle = FontStyle.Normal;
+
             switch (fontFamilyExpression.Length)
             {
                 case 1:
                     {
-                        return new FontFamily(fontFamilyExpression[0]);
+                        familyName = fontFamilyExpression[0];
+                        break;
                     }
                 case 2:
                     {
-                        return new FontFamily(fontFamilyExpression[1], new Uri(fontFamilyExpression[0], UriKind.RelativeOrAbsolute));
+                        baseUri = new Uri(fontFamilyExpression[0], UriKind.RelativeOrAbsolute);
+                        familyName = fontFamilyExpression[1];
+                        break;
                     }
+                //case 3:
+                //    {
+                //        baseUri = new Uri(fontFamilyExpression[0], UriKind.RelativeOrAbsolute);
+                //        familyName = fontFamilyExpression[1];
+                //        fontWeight = (FontWeight)Enum.Parse(typeof(FontWeight), fontFamilyExpression[2]);
+                //        break;
+                //    }
+                //case 4:
+                //    {
+                //        baseUri = new Uri(fontFamilyExpression[0], UriKind.RelativeOrAbsolute);
+                //        familyName = fontFamilyExpression[1];
+                //        fontWeight = (FontWeight)Enum.Parse(typeof(FontWeight), fontFamilyExpression[2]);
+                //        fontStyle = (FontStyle)Enum.Parse(typeof(FontStyle), fontFamilyExpression[3]);
+                //        break;
+                //    }
                 default:
                     {
                         throw new ArgumentException("Specified family is not supported.");
                     }
             }
+
+            var fontFamily = new FontFamily(familyName, baseUri);
+
+            var cachedFontFamily = AvaloniaLocator.Current.GetService<IFontFamilyCache>().GetOrAddFontFamily(fontFamily);
+
+            cachedFontFamily.GetOrAddFamilyTypeface(baseUri, fontWeight, fontStyle);
+
+            return fontFamily;
         }
     }
 }

+ 5 - 1
src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs

@@ -28,7 +28,11 @@ namespace Avalonia.Direct2D1.Media
 
             if (typeface.FontFamily.BaseUri != null)
             {
-                var fontLoader = new ResourceFontLoader(factory, typeface.FontFamily.BaseUri);
+                var fontFamily = AvaloniaLocator.Current.GetService<IFontFamilyCache>().GetOrAddFontFamily(typeface.FontFamily);
+
+                fontFamily.TryGetFamilyTypeface(out var familyTypeface);
+
+                var fontLoader = new ResourceFontLoader(factory, familyTypeface.ResourceUri);
 
                 var fontCollection = new DWrite.FontCollection(factory, fontLoader, fontLoader.Key);