From 1ace4293427a3828dbd3bf78b5f58e13efafd7ae Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Tue, 1 May 2018 20:24:53 +0200 Subject: [PATCH] Direct2D1 caching --- samples/ControlCatalog.Desktop/Program.cs | 1 - .../Assets/octin_stencil_free.ttf | Bin 0 -> 103128 bytes samples/ControlCatalog/ControlCatalog.csproj | 1 + samples/ControlCatalog/Pages/BorderPage.xaml | 4 +- src/Avalonia.Visuals/Media/FontFamily.cs | 207 +++++++++--------- .../Converters/FontFamilyTypeConverter.cs | 29 +-- .../Media/FormattedTextImpl.cs | 152 ++++++------- 7 files changed, 181 insertions(+), 213 deletions(-) create mode 100644 samples/ControlCatalog/Assets/octin_stencil_free.ttf diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index df17aabb00..daa6ba69db 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -16,7 +16,6 @@ namespace ControlCatalog { // TODO: Make this work with GTK/Skia/Cairo depending on command-line args // again. - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new FontFamilyCache()); BuildAvaloniaApp().Start(); } diff --git a/samples/ControlCatalog/Assets/octin_stencil_free.ttf b/samples/ControlCatalog/Assets/octin_stencil_free.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6acd53279b776e2b2cbd57f111b685050367ee4f GIT binary patch literal 103128 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 z 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 literal 0 HcmV?d00001 diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index 291c9283be..beb51f42fc 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -13,6 +13,7 @@ + diff --git a/samples/ControlCatalog/Pages/BorderPage.xaml b/samples/ControlCatalog/Pages/BorderPage.xaml index a95bc945ae..dc0b05686b 100644 --- a/samples/ControlCatalog/Pages/BorderPage.xaml +++ b/samples/ControlCatalog/Pages/BorderPage.xaml @@ -27,8 +27,8 @@ Padding="16"> Rounded Corners - Rounded Corners - Rounded Corners + Rounded Corners + Rounded Corners diff --git a/src/Avalonia.Visuals/Media/FontFamily.cs b/src/Avalonia.Visuals/Media/FontFamily.cs index 9293432461..7442619b5c 100644 --- a/src/Avalonia.Visuals/Media/FontFamily.cs +++ b/src/Avalonia.Visuals/Media/FontFamily.cs @@ -2,50 +2,33 @@ // 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 { - public FontFamily(string familyName) : this(familyName, null) { } - - public FontFamily(string familyName, Uri baseUri) + public FontFamily(string familyName = "Courier New", Uri baseUri = null) { if (familyName == null) throw new ArgumentNullException(nameof(familyName)); - FontFamilyKey = new FontFamilyKey(familyName, baseUri); + Key = new FontFamilyKey(familyName, baseUri); } - public string Name => FontFamilyKey.FriendlyName; + public string Name => Key.FriendlyName; - public Uri BaseUri => FontFamilyKey.BaseUri; + public Uri BaseUri => Key.BaseUri; - internal FontFamilyKey FontFamilyKey { get; } - } + public FontFamilyKey Key { get; } - public class FamilyTypeface - { - public FamilyTypeface(Uri resourceUri = null, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) + public override string ToString() { - ResourceUri = resourceUri; - FontStyle = fontStyle; - FontWeight = fontWeight; + return Key.ToString(); } - - public Uri ResourceUri { get; } - public FontWeight FontWeight { get; } - public FontStyle FontStyle { get; } } public class FontFamilyKey { - public FontFamilyKey(string friendlyName) : this(friendlyName, null) { } - - public FontFamilyKey(string friendlyName, Uri baseUri) + public FontFamilyKey(string friendlyName, Uri baseUri = null) { FriendlyName = friendlyName; BaseUri = baseUri; @@ -85,87 +68,111 @@ namespace Avalonia.Media return true; } - } - public class FamilyTypefaceKey - { - public FamilyTypefaceKey(FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) - { - FontWeight = fontWeight; - FontStyle = fontStyle; - } - - public FontWeight FontWeight { get; } - - public FontStyle FontStyle { get; } - - public override int GetHashCode() + public override string ToString() { - unchecked + if (BaseUri != null) { - var hash = (int)2166136261; - - hash = (hash * 16777619) ^ FontWeight.GetHashCode(); - - hash = (hash * 16777619) ^ FontStyle.GetHashCode(); - - return hash; + return BaseUri + "#" + FriendlyName; } - } - - 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; + return FriendlyName; } } - public class CachedFontFamily - { - private readonly ConcurrentDictionary _typefaces = - new ConcurrentDictionary(); - - public IEnumerable 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 FamilyTypeface GetOrAddFamilyTypeface(Uri resourceUri, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) - { - return _typefaces.GetOrAdd(new FamilyTypefaceKey(fontWeight, fontStyle), x => CreateFamilyTypeface(x, resourceUri)); - } - - private static FamilyTypeface CreateFamilyTypeface(FamilyTypefaceKey familyTypefaceKey, Uri resourceUri) - { - return new FamilyTypeface(resourceUri, familyTypefaceKey.FontWeight, familyTypefaceKey.FontStyle); - } - } - - public interface IFontFamilyCache - { - CachedFontFamily GetOrAddFontFamily(FontFamily fontFamily); - } - - public class FontFamilyCache : IFontFamilyCache - { - private readonly ConcurrentDictionary _cachedFontFamilies = new ConcurrentDictionary(); - - public CachedFontFamily GetOrAddFontFamily(FontFamily fontFamily) - { - return _cachedFontFamilies.GetOrAdd(fontFamily.FontFamilyKey, CreateCachedFontFamily); - } - - private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey) - { - return new CachedFontFamily(); - } - } + //public class FamilyTypeface + //{ + // public FamilyTypeface(Uri resourceUri = null, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) + // { + // ResourceUri = resourceUri; + // FontStyle = fontStyle; + // FontWeight = fontWeight; + // } + + // public Uri ResourceUri { get; } + // public FontWeight FontWeight { get; } + // public FontStyle FontStyle { get; } + //} + + //public class FamilyTypefaceKey + //{ + // public FamilyTypefaceKey(FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) + // { + // FontWeight = fontWeight; + // FontStyle = fontStyle; + // } + + // public FontWeight FontWeight { get; } + + // public FontStyle FontStyle { get; } + + // public override int GetHashCode() + // { + // unchecked + // { + // var hash = (int)2166136261; + + // hash = (hash * 16777619) ^ FontWeight.GetHashCode(); + + // hash = (hash * 16777619) ^ FontStyle.GetHashCode(); + + // return hash; + // } + // } + + // 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; + // } + //} + + //public class CachedFontFamily + //{ + // private readonly ConcurrentDictionary _typefaces = + // new ConcurrentDictionary(); + + // public bool TryGetFamilyTypeface(out FamilyTypeface typeface, FontWeight fontWeight = FontWeight.Normal, + // FontStyle fontStyle = FontStyle.Normal) + // { + // return _typefaces.TryGetValue(new FamilyTypefaceKey(fontWeight, fontStyle), out typeface); + // } + + // public bool TryAddFamilyTypeface(Uri resourceUri, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) + // { + // var familyTypefaceKeytypefaceKey = new FamilyTypefaceKey(fontWeight, fontStyle); + + // return _typefaces.TryAdd(familyTypefaceKeytypefaceKey, CreateFamilyTypeface(familyTypefaceKeytypefaceKey, resourceUri)); + // } + + // private static FamilyTypeface CreateFamilyTypeface(FamilyTypefaceKey familyTypefaceKey, Uri resourceUri) + // { + // return new FamilyTypeface(resourceUri, familyTypefaceKey.FontWeight, familyTypefaceKey.FontStyle); + // } + //} + + //public class FontFamilyCache + //{ + // private readonly ConcurrentDictionary _cachedFontFamilies = new ConcurrentDictionary(); + + // public bool TryGetCachedFontFamily(FontFamily fontFamily, out CachedFontFamily cachedFontFamily) + // { + // return _cachedFontFamilies.TryGetValue(fontFamily.Key, out cachedFontFamily); + // } + + // public CachedFontFamily GetOrAddCachedFontFamily(FontFamily fontFamily) + // { + // return _cachedFontFamilies.GetOrAdd(fontFamily.Key, CreateCachedFontFamily); + // } + + // private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey) + // { + // return new CachedFontFamily(); + // } + //} } diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs index 6689b47c2f..6cd7c24632 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs @@ -18,16 +18,14 @@ namespace Avalonia.Markup.Xaml.Converters if (string.IsNullOrEmpty(s)) throw new ArgumentException("Specified family is not supported."); + if (!s.StartsWith("resm:")) return new FontFamily(s); + var fontFamilyExpression = s.Split('#'); string familyName; Uri baseUri = null; - var fontWeight = FontWeight.Normal; - - var fontStyle = FontStyle.Normal; - switch (fontFamilyExpression.Length) { case 1: @@ -41,34 +39,13 @@ namespace Avalonia.Markup.Xaml.Converters 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().GetOrAddFontFamily(fontFamily); - - cachedFontFamily.GetOrAddFamilyTypeface(baseUri, fontWeight, fontStyle); - - return fontFamily; + return new FontFamily(familyName, baseUri); } } } \ No newline at end of file diff --git a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs index 20fc956b5d..57beac652c 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs @@ -2,8 +2,8 @@ // 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.IO; using System.Linq; using Avalonia.Media; using Avalonia.Platform; @@ -26,59 +26,46 @@ namespace Avalonia.Direct2D1.Media var factory = AvaloniaLocator.Current.GetService(); + DWrite.TextFormat textFormat; + if (typeface.FontFamily.BaseUri != null) { - var fontFamily = AvaloniaLocator.Current.GetService().GetOrAddFontFamily(typeface.FontFamily); - - fontFamily.TryGetFamilyTypeface(out var familyTypeface); - - var fontLoader = new ResourceFontLoader(factory, familyTypeface.ResourceUri); + var fontCollection = Direct2D1CustomFontResourceCache.GetOrAddCustomFontResource(typeface.FontFamily, factory); - var fontCollection = new DWrite.FontCollection(factory, fontLoader, fontLoader.Key); - - using (var textFormat = - new DWrite.TextFormat(factory, typeface.FontFamily.Name, fontCollection, DWrite.FontWeight.Normal, - DWrite.FontStyle.Normal, DWrite.FontStretch.Normal, (float)typeface.FontSize)) - { - textFormat.TextAlignment = DWrite.TextAlignment.Center; - textFormat.ParagraphAlignment = DWrite.ParagraphAlignment.Center; - - textFormat.WordWrapping = wrapping == TextWrapping.Wrap ? - DWrite.WordWrapping.Wrap : - DWrite.WordWrapping.NoWrap; - - TextLayout = new DWrite.TextLayout(factory, Text ?? string.Empty, textFormat, (float)constraint.Width, - (float)constraint.Height) - { - TextAlignment = textAlignment.ToDirect2D() - }; - } + textFormat = new DWrite.TextFormat( + factory, + typeface.FontFamily.Name, + fontCollection, + (DWrite.FontWeight)typeface.Weight, + (DWrite.FontStyle)typeface.Style, + DWrite.FontStretch.Normal, + (float)typeface.FontSize); } else { - using (var format = new DWrite.TextFormat( + textFormat = new DWrite.TextFormat( factory, - typeface?.FontFamily.Name ?? "Courier New", - (DWrite.FontWeight)(typeface.Weight), - (DWrite.FontStyle)(typeface.Style), - (float)typeface.FontSize)) - { - format.WordWrapping = wrapping == TextWrapping.Wrap ? - DWrite.WordWrapping.Wrap : - DWrite.WordWrapping.NoWrap; - - TextLayout = new DWrite.TextLayout( - factory, - text ?? string.Empty, - format, - (float)constraint.Width, - (float)constraint.Height) - { - TextAlignment = textAlignment.ToDirect2D() - }; - } + typeface.FontFamily.Name, + (DWrite.FontWeight)typeface.Weight, + (DWrite.FontStyle)typeface.Style, + (float)typeface.FontSize); } + textFormat.TextAlignment = DWrite.TextAlignment.Center; + textFormat.ParagraphAlignment = DWrite.ParagraphAlignment.Center; + + textFormat.WordWrapping = wrapping == TextWrapping.Wrap ? + DWrite.WordWrapping.Wrap : + DWrite.WordWrapping.NoWrap; + + TextLayout = new DWrite.TextLayout(factory, Text ?? string.Empty, textFormat, (float)constraint.Width, + (float)constraint.Height) + { + TextAlignment = textAlignment.ToDirect2D() + }; + + textFormat.Dispose(); + if (spans != null) { foreach (var span in spans) @@ -98,10 +85,10 @@ namespace Avalonia.Direct2D1.Media public DWrite.TextLayout TextLayout { get; } - public void Dispose() - { - TextLayout.Dispose(); - } + //public void Dispose() + //{ + // TextLayout.Dispose(); + //} public IEnumerable GetLines() { @@ -111,14 +98,11 @@ namespace Avalonia.Direct2D1.Media public TextHitTestResult HitTestPoint(Point point) { - SharpDX.Mathematics.Interop.RawBool isTrailingHit; - SharpDX.Mathematics.Interop.RawBool isInside; - var result = TextLayout.HitTestPoint( (float)point.X, (float)point.Y, - out isTrailingHit, - out isInside); + out var isTrailingHit, + out var isInside); return new TextHitTestResult { @@ -130,14 +114,7 @@ namespace Avalonia.Direct2D1.Media public Rect HitTestTextPosition(int index) { - float x; - float y; - - var result = TextLayout.HitTestTextPosition( - index, - false, - out x, - out y); + var result = TextLayout.HitTestTextPosition(index, false, out _, out _); return new Rect(result.Left, result.Top, result.Width, result.Height); } @@ -175,12 +152,29 @@ namespace Avalonia.Direct2D1.Media } } + internal static class Direct2D1CustomFontResourceCache + { + private static readonly ConcurrentDictionary s_cachedFonts = + new ConcurrentDictionary(); + + public static DWrite.FontCollection GetOrAddCustomFontResource(FontFamily fontFamily, DWrite.Factory factory) + { + return s_cachedFonts.GetOrAdd(fontFamily.Key, x => CreateCustomFontResource(x, factory)); + } + + private static DWrite.FontCollection CreateCustomFontResource(FontFamilyKey fontFamilyKey, DWrite.Factory factory) + { + var fontLoader = new ResourceFontLoader(factory, fontFamilyKey.BaseUri); + + return new DWrite.FontCollection(factory, fontLoader, fontLoader.Key); + } + } + public class ResourceFontLoader : CallbackBase, DWrite.FontCollectionLoader, DWrite.FontFileLoader { private readonly List _fontStreams = new List(); private readonly List _enumerators = new List(); private readonly DataStream _keyStream; - private readonly DWrite.Factory _factory; ///

@@ -190,7 +184,7 @@ namespace Avalonia.Direct2D1.Media /// public ResourceFontLoader(DWrite.Factory factory, Uri fontResource) { - _factory = factory; + var factory1 = factory; var assets = AvaloniaLocator.Current.GetService(); @@ -215,8 +209,8 @@ namespace Avalonia.Direct2D1.Media _keyStream.Position = 0; // Register the - _factory.RegisterFontFileLoader(this); - _factory.RegisterFontCollectionLoader(this); + factory1.RegisterFontFileLoader(this); + factory1.RegisterFontCollectionLoader(this); } @@ -224,13 +218,7 @@ namespace Avalonia.Direct2D1.Media /// Gets the key used to identify the FontCollection as well as storing index for fonts. /// /// The key. - public DataStream Key - { - get - { - return _keyStream; - } - } + public DataStream Key => _keyStream; /// /// Creates a font file enumerator object that encapsulates a collection of font files. The font system calls back to this interface to create a font collection. @@ -282,7 +270,7 @@ namespace Avalonia.Direct2D1.Media /// The stream. public ResourceFontFileStream(DataStream stream) { - this._stream = stream; + _stream = stream; } /// @@ -384,19 +372,15 @@ namespace Avalonia.Direct2D1.Media { bool moveNext = keyStream.RemainingLength != 0; - if (moveNext) - { - if (_currentFontFile != null) - { - _currentFontFile.Dispose(); - } + if (!moveNext) return false; - _currentFontFile = new DWrite.FontFile(_factory, keyStream.PositionPointer, 4, _loader); + _currentFontFile?.Dispose(); - keyStream.Position += 4; - } + _currentFontFile = new DWrite.FontFile(_factory, keyStream.PositionPointer, 4, _loader); + + keyStream.Position += 4; - return moveNext; + return true; } ///