Browse Source

New asset loader

Added unit test for wildcard
pull/1564/head
Benedikt Schroeder 8 years ago
parent
commit
a59cf3a135
  1. 26
      src/Avalonia.Base/Platform/IAssetLoader.cs
  2. 7
      src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs
  3. 34
      src/Shared/PlatformSupport/AssetLoader.cs
  4. 7
      tests/Avalonia.UnitTests/MockAssetLoader.cs
  5. 42
      tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs

26
src/Avalonia.Base/Platform/IAssetLoader.cs

@ -19,8 +19,8 @@ namespace Avalonia.Platform
/// AssetLoader needs a refactor cause right now it lives in 3+ platforms which /// AssetLoader needs a refactor cause right now it lives in 3+ platforms which
/// can all be loaded on Windows. /// can all be loaded on Windows.
/// </summary> /// </summary>
/// <param name="asm"></param> /// <param name="assembly"></param>
void SetDefaultAssembly(Assembly asm); void SetDefaultAssembly(Assembly assembly);
/// <summary> /// <summary>
/// Checks if an asset with the specified URI exists. /// Checks if an asset with the specified URI exists.
@ -33,39 +33,39 @@ namespace Avalonia.Platform
bool Exists(Uri uri, Uri baseUri = null); bool Exists(Uri uri, Uri baseUri = null);
/// <summary> /// <summary>
/// Opens the resource with the requested URI. /// Opens the asset with the requested URI.
/// </summary> /// </summary>
/// <param name="uri">The URI.</param> /// <param name="uri">The URI.</param>
/// <param name="baseUri"> /// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative. /// A base URI to use if <paramref name="uri"/> is relative.
/// </param> /// </param>
/// <returns>A stream containing the resource contents.</returns> /// <returns>A stream containing the asset contents.</returns>
/// <exception cref="FileNotFoundException"> /// <exception cref="FileNotFoundException">
/// The resource was not found. /// The asset could not be found.
/// </exception> /// </exception>
Stream Open(Uri uri, Uri baseUri = null); Stream Open(Uri uri, Uri baseUri = null);
/// <summary> /// <summary>
/// Opens the resource with the requested URI and returns the resource string and the /// Opens the asset with the requested URI and returns the asset stream and the
/// assembly containing the resource. /// assembly containing the asset.
/// </summary> /// </summary>
/// <param name="uri">The URI.</param> /// <param name="uri">The URI.</param>
/// <param name="baseUri"> /// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative. /// A base URI to use if <paramref name="uri"/> is relative.
/// </param> /// </param>
/// <returns> /// <returns>
/// The stream containing the resource contents together with the assembly. /// The stream containing the asset contents together with the assembly.
/// </returns> /// </returns>
/// <exception cref="FileNotFoundException"> /// <exception cref="FileNotFoundException">
/// The resource was not found. /// The asset could not be found.
/// </exception> /// </exception>
(Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null); (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null);
/// <summary> /// <summary>
/// Gets all assets at a specific location. /// Gets all assets of a folder and subfolders that match specified uri.
/// </summary> /// </summary>
/// <param name="location">The location of assets.</param> /// <param name="uri">The URI.</param>
/// <returns>A tuple containing the absolute path to the resource and the owner assembly</returns> /// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri location); IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri uri);
} }
} }

7
src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs

@ -34,9 +34,7 @@ namespace Avalonia.Media.Fonts
{ {
var availableAssets = s_assetLoader.GetAssets(location); var availableAssets = s_assetLoader.GetAssets(location);
var locationPath = location.AbsolutePath; var matchingAssets = availableAssets.Where(x => x.absolutePath.EndsWith(".ttf"));
var matchingAssets = availableAssets.Where(x => x.absolutePath.Contains(locationPath) && x.absolutePath.EndsWith(".ttf"));
return matchingAssets.Select(x => GetAssetUri(x.absolutePath, x.assembly)); return matchingAssets.Select(x => GetAssetUri(x.absolutePath, x.assembly));
} }
@ -54,7 +52,8 @@ namespace Avalonia.Media.Fonts
var compareTo = location.AbsolutePath + "." + fileName.Split('*').First(); var compareTo = location.AbsolutePath + "." + fileName.Split('*').First();
var matchingResources = availableResources.Where(x => x.absolutePath.Contains(compareTo)); var matchingResources =
availableResources.Where(x => x.absolutePath.Contains(compareTo) && x.absolutePath.EndsWith(".ttf"));
return matchingResources.Select(x => GetAssetUri(x.absolutePath, x.assembly)); return matchingResources.Select(x => GetAssetUri(x.absolutePath, x.assembly));
} }

34
src/Shared/PlatformSupport/AssetLoader.cs

@ -57,21 +57,21 @@ namespace Avalonia.Shared.PlatformSupport
} }
/// <summary> /// <summary>
/// Opens the resource with the requested URI. /// Opens the asset with the requested URI.
/// </summary> /// </summary>
/// <param name="uri">The URI.</param> /// <param name="uri">The URI.</param>
/// <param name="baseUri"> /// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative. /// A base URI to use if <paramref name="uri"/> is relative.
/// </param> /// </param>
/// <returns>A stream containing the resource contents.</returns> /// <returns>A stream containing the asset contents.</returns>
/// <exception cref="FileNotFoundException"> /// <exception cref="FileNotFoundException">
/// The resource was not found. /// The asset could not be found.
/// </exception> /// </exception>
public Stream Open(Uri uri, Uri baseUri = null) => OpenAndGetAssembly(uri, baseUri).stream; public Stream Open(Uri uri, Uri baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1;
/// <summary> /// <summary>
/// Opens the resource with the requested URI and returns the resource string and the /// Opens the asset with the requested URI and returns the asset stream and the
/// assembly containing the resource. /// assembly containing the asset.
/// </summary> /// </summary>
/// <param name="uri">The URI.</param> /// <param name="uri">The URI.</param>
/// <param name="baseUri"> /// <param name="baseUri">
@ -81,7 +81,7 @@ namespace Avalonia.Shared.PlatformSupport
/// The stream containing the resource contents together with the assembly. /// The stream containing the resource contents together with the assembly.
/// </returns> /// </returns>
/// <exception cref="FileNotFoundException"> /// <exception cref="FileNotFoundException">
/// The resource was not found. /// The asset could not be found.
/// </exception> /// </exception>
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null) public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null)
{ {
@ -95,11 +95,17 @@ namespace Avalonia.Shared.PlatformSupport
return (asset.GetStream(), asset.Assembly); return (asset.GetStream(), asset.Assembly);
} }
public IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri location) /// <summary>
/// Gets all assets of a folder and subfolders that match specified uri.
/// </summary>
/// <param name="uri">The URI.</param>
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
public IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri uri)
{ {
var assembly = GetAssembly(location); var assembly = GetAssembly(uri);
return assembly?.Resources.Select(x => (x.Key, x.Value.Assembly)) ?? return assembly?.Resources.Where(x => x.Key.Contains(uri.AbsolutePath))
.Select(x => (x.Key, x.Value.Assembly)) ??
Enumerable.Empty<(string AbsolutePath, Assembly Assembly)>(); Enumerable.Empty<(string AbsolutePath, Assembly Assembly)>();
} }
@ -130,8 +136,9 @@ namespace Avalonia.Shared.PlatformSupport
if (uri != null) if (uri != null)
{ {
var qs = ParseQueryString(uri); var qs = ParseQueryString(uri);
string assemblyName;
if (qs.TryGetValue("assembly", out var assemblyName)) if (qs.TryGetValue("assembly", out assemblyName))
{ {
return GetAssembly(assemblyName); return GetAssembly(assemblyName);
} }
@ -147,7 +154,8 @@ namespace Avalonia.Shared.PlatformSupport
return _defaultAssembly; return _defaultAssembly;
} }
if (!AssemblyNameCache.TryGetValue(name, out var rv)) AssemblyDescriptor rv;
if (!AssemblyNameCache.TryGetValue(name, out rv))
{ {
var loadedAssemblies = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies(); var loadedAssemblies = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies();
var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name); var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name);
@ -225,4 +233,4 @@ namespace Avalonia.Shared.PlatformSupport
public string Name { get; } public string Name { get; }
} }
} }
} }

7
tests/Avalonia.UnitTests/MockAssetLoader.cs

@ -26,15 +26,16 @@ namespace Avalonia.UnitTests
{ {
return new MemoryStream(Encoding.UTF8.GetBytes(_assets[uri])); return new MemoryStream(Encoding.UTF8.GetBytes(_assets[uri]));
} }
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null) public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null)
{ {
return (Open(uri, baseUri), (Assembly)null); return (Open(uri, baseUri), (Assembly)null);
} }
public IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri location) public IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri uri)
{ {
return _assets.Keys.Select(x => (x.AbsolutePath, Assembly.GetEntryAssembly())); return _assets.Keys.Where(x => x.AbsolutePath.Contains(uri.AbsolutePath))
.Select(x => (x.AbsolutePath, Assembly.GetEntryAssembly()));
} }
public void SetDefaultAssembly(Assembly asm) public void SetDefaultAssembly(Assembly asm)

42
tests/Avalonia.Visuals.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs

@ -11,20 +11,50 @@ namespace Avalonia.Visuals.UnitTests.Media.Fonts
{ {
public class FontFamilyLoaderTests public class FontFamilyLoaderTests
{ {
private const string fontName = "#MyFont";
private const string assembly = "?assembly=Avalonia.Visuals.UnitTests";
private const string assetLocation = "resm:Avalonia.Visuals.UnitTests.Assets";
[Fact]
public void Should_Load_Single_FontAsset()
{
const string fontAsset = assetLocation + ".MyFont-Regular.ttf" + assembly + fontName;
using (StartWithResources((fontAsset, "AssetData")))
{
var source = new Uri(fontAsset, UriKind.RelativeOrAbsolute);
var key = new FontFamilyKey(source);
var fontAssets = FontFamilyLoader.LoadFontAssets(key);
Assert.Single(fontAssets);
}
}
[Fact] [Fact]
public void Should_Load_Single_FontResource() public void Should_Load_Matching_Assets()
{ {
const string resourcePath = "resm:Avalonia.Visuals.UnitTests.Assets.MyFont.ttf?assembly=Avalonia.Visuals.UnitTests#MyFont"; const string assetMyFontRegular = assetLocation + ".MyFont-Regular.ttf" + assembly + fontName;
const string assetMyFontBold = assetLocation + ".MyFont-Bold.ttf" + assembly + fontName;
const string assetYourFont = assetLocation + ".YourFont.ttf" + assembly + fontName;
var fontLocations = new[]
{
(assetMyFontRegular, "AssetData"),
(assetMyFontBold, "AssetData"),
(assetYourFont, "AssetData")
};
using (StartWithResources((resourcePath, "MyFont.ttf"))) using (StartWithResources(fontLocations))
{ {
var source = new Uri(resourcePath, UriKind.RelativeOrAbsolute); var source = new Uri(assetLocation + ".MyFont-*.ttf", UriKind.RelativeOrAbsolute);
var key = new FontFamilyKey(source); var key = new FontFamilyKey(source);
var resources = FontFamilyLoader.LoadFontAssets(key); var fontAssets = FontFamilyLoader.LoadFontAssets(key);
Assert.Single(resources); Assert.Equal(2, fontAssets.Count());
} }
} }

Loading…
Cancel
Save