|
|
|
@ -1,5 +1,10 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Concurrent; |
|
|
|
using System.Reflection; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using Avalonia.Media; |
|
|
|
using Avalonia.Media.Fonts; |
|
|
|
using Avalonia.UnitTests; |
|
|
|
using Xunit; |
|
|
|
|
|
|
|
@ -86,5 +91,59 @@ namespace Avalonia.Base.UnitTests.Media |
|
|
|
Assert.Equal("DejaVu", FontManager.Current.DefaultFontFamily.Name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task TryGetGlyphTypeface_Should_Be_Thread_Safe_For_Embedded_Fonts() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) |
|
|
|
{ |
|
|
|
var fontManager = FontManager.Current; |
|
|
|
var fontCollections = (ConcurrentDictionary<Uri, IFontCollection>) |
|
|
|
typeof(FontManager) |
|
|
|
.GetField("_fontCollections", BindingFlags.NonPublic | BindingFlags.Instance)! |
|
|
|
.GetValue(fontManager)!; |
|
|
|
|
|
|
|
const string fontUri = |
|
|
|
"resm:Avalonia.Base.UnitTests.Assets?assembly=Avalonia.Base.UnitTests#Noto Mono"; |
|
|
|
var collectionKey = |
|
|
|
new Uri("resm:Avalonia.Base.UnitTests.Assets?assembly=Avalonia.Base.UnitTests"); |
|
|
|
|
|
|
|
// Warm up to validate the font URI is correct.
|
|
|
|
Assert.True(fontManager.TryGetGlyphTypeface(new Typeface(new FontFamily(fontUri)), out _)); |
|
|
|
|
|
|
|
const int iterations = 50; |
|
|
|
int failures = 0; |
|
|
|
|
|
|
|
for (int i = 0; i < iterations; i++) |
|
|
|
{ |
|
|
|
// Remove the cached collection so both threads must re-create it.
|
|
|
|
fontCollections.TryRemove(collectionKey, out _); |
|
|
|
|
|
|
|
using var barrier = new Barrier(2); |
|
|
|
bool r1 = false, r2 = false; |
|
|
|
|
|
|
|
var t1 = Task.Run(() => |
|
|
|
{ |
|
|
|
barrier.SignalAndWait(); |
|
|
|
r1 = fontManager.TryGetGlyphTypeface( |
|
|
|
new Typeface(new FontFamily(fontUri)), out _); |
|
|
|
}); |
|
|
|
|
|
|
|
var t2 = Task.Run(() => |
|
|
|
{ |
|
|
|
barrier.SignalAndWait(); |
|
|
|
r2 = fontManager.TryGetGlyphTypeface( |
|
|
|
new Typeface(new FontFamily(fontUri)), out _); |
|
|
|
}); |
|
|
|
|
|
|
|
await Task.WhenAll(t1, t2); |
|
|
|
|
|
|
|
if (!r1 || !r2) |
|
|
|
Interlocked.Increment(ref failures); |
|
|
|
} |
|
|
|
|
|
|
|
Assert.Equal(0, failures); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|