Browse Source

Use `avares://` scheme with proper relative uri handling

pull/2104/head
Nikita Tsukanov 7 years ago
parent
commit
b092c51a55
  1. 4
      samples/ControlCatalog/App.xaml
  2. 2
      samples/ControlCatalog/MainWindow.xaml
  3. 8
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  4. 2
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  5. 4
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  6. 52
      src/Shared/PlatformSupport/AssetLoader.cs
  7. 1
      src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs

4
samples/ControlCatalog/App.xaml

@ -2,8 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.App">
<Application.Styles>
<StyleInclude Source="res:asm:Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="res:asm:Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<Style Selector="TextBlock.h1">
<Setter Property="FontSize" Value="{DynamicResource FontSizeLarge}"/>
<Setter Property="FontWeight" Value="Medium"/>

2
samples/ControlCatalog/MainWindow.xaml

@ -1,6 +1,6 @@
<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
Title="Avalonia Control Gallery"
Icon="/Assets/test_icon.ico?assembly=ControlCatalog"
Icon="/Assets/test_icon.ico"
xmlns:local="clr-namespace:ControlCatalog"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.MainWindow">

8
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -44,10 +44,10 @@
<StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Classes="h2">res fonts</TextBlock>
<TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="res:asm:ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="res:asm:ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="res:asm:ControlCatalog/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="res:asm:ControlCatalog/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="avares://ControlCatalog/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="avares://ControlCatalog/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/>
</StackPanel>
</StackPanel>
</StackPanel>

2
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@ -30,7 +30,7 @@ namespace Avalonia.DesignerSupport
xamlFileProjectPath = "/Designer/Fake.xaml";
//Fabricate fake Uri
baseUri =
new Uri($"res:asm:{Path.GetFileNameWithoutExtension(assemblyPath)}{xamlFileProjectPath}");
new Uri($"avares://{Path.GetFileNameWithoutExtension(assemblyPath)}{xamlFileProjectPath}");
}
var localAsm = assemblyPath != null ? Assembly.LoadFile(Path.GetFullPath(assemblyPath)) : null;

4
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@ -231,7 +231,7 @@ namespace Avalonia.Markup.Xaml
private static IEnumerable<Uri> GetUrisFor(IAssetLoader assetLocator, Type type)
{
var asm = type.GetTypeInfo().Assembly.GetName().Name;
var xamlInfoUri = new Uri($"res:asm:{asm}/!AvaloniaResourceXamlInfo");
var xamlInfoUri = new Uri($"avares://{asm}/!AvaloniaResourceXamlInfo");
var typeName = type.FullName;
if (typeName == null)
throw new ArgumentException("Type doesn't have a FullName");
@ -243,7 +243,7 @@ namespace Avalonia.Markup.Xaml
var xamlInfo = (AvaloniaResourceXamlInfo)s_xamlInfoSerializer.ReadObject(xamlInfoStream);
if (xamlInfo.ClassToResourcePathIndex.TryGetValue(typeName, out var rv) == true)
{
yield return new Uri($"res:asm:{asm}{rv}");
yield return new Uri($"avares://{asm}{rv}");
yield break;
}
}

52
src/Shared/PlatformSupport/AssetLoader.cs

@ -20,20 +20,20 @@ namespace Avalonia.Shared.PlatformSupport
private static readonly Dictionary<string, AssemblyDescriptor> AssemblyNameCache
= new Dictionary<string, AssemblyDescriptor>();
private AssemblyDescriptor _defaultAssembly;
private AssemblyDescriptor _defaultResmAssembly;
/// <summary>
/// Initializes a new instance of the <see cref="AssetLoader"/> class.
/// </summary>
/// <param name="assembly">
/// The default assembly from which to load assets for which no assembly is specified.
/// The default assembly from which to load resm: assets for which no assembly is specified.
/// </param>
public AssetLoader(Assembly assembly = null)
{
if (assembly == null)
assembly = Assembly.GetEntryAssembly();
if (assembly != null)
_defaultAssembly = new AssemblyDescriptor(assembly);
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
@ -42,7 +42,7 @@ namespace Avalonia.Shared.PlatformSupport
/// <param name="assembly">The default assembly.</param>
public void SetDefaultAssembly(Assembly assembly)
{
_defaultAssembly = new AssemblyDescriptor(assembly);
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
@ -115,7 +115,7 @@ namespace Avalonia.Shared.PlatformSupport
}
uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "res")
if (uri.Scheme == "avares")
{
var (asm, path) = GetResAsmAndPath(uri);
if (asm == null)
@ -129,7 +129,7 @@ namespace Avalonia.Shared.PlatformSupport
return Enumerable.Empty<Uri>();
path = path.TrimEnd('/') + '/';
return asm.AvaloniaResources.Where(r => r.Key.StartsWith(path))
.Select(x => new Uri($"res:asm:{asm.Name}{x.Key}"));
.Select(x => new Uri($"avares://{asm.Name}{x.Key}"));
}
return Enumerable.Empty<Uri>();
@ -153,7 +153,7 @@ namespace Avalonia.Shared.PlatformSupport
{
if (uri.IsAbsoluteUri && uri.Scheme == "resm")
{
var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultAssembly;
var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultResmAssembly;
if (asm == null)
{
@ -171,13 +171,9 @@ namespace Avalonia.Shared.PlatformSupport
uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "res")
if (uri.Scheme == "avares")
{
var (asm, path) = GetResAsmAndPath(uri);
if(asm == null)
throw new ArgumentException(
"No default assembly, entry assembly or explicit assembly specified; " +
"don't know where to look up for the resource, try specifying assembly explicitly.");
if (asm.AvaloniaResources == null)
return null;
asm.AvaloniaResources.TryGetValue(path, out var desc);
@ -189,18 +185,8 @@ namespace Avalonia.Shared.PlatformSupport
private (AssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri)
{
string path = null, asmPart = null;
if (!uri.AbsolutePath.StartsWith("asm:"))
path = uri.AbsolutePath;
else
{
var sp = uri.AbsolutePath.Split(new[] {'/'}, 2);
asmPart = sp[0].Substring(4);
path = '/' + sp[1];
}
var asm = (asmPart == null ? null : GetAssembly(asmPart)) ?? _defaultAssembly;
return (asm, path);
var asm = GetAssembly(uri.Authority);
return (asm, uri.AbsolutePath);
}
private AssemblyDescriptor GetAssembly(Uri uri)
@ -209,7 +195,7 @@ namespace Avalonia.Shared.PlatformSupport
{
if (!uri.IsAbsoluteUri)
return null;
if (uri.Scheme == "res")
if (uri.Scheme == "avares")
return GetResAsmAndPath(uri).asm;
if (uri.Scheme == "resm")
@ -230,9 +216,7 @@ namespace Avalonia.Shared.PlatformSupport
private AssemblyDescriptor GetAssembly(string name)
{
if (name == null)
{
return _defaultAssembly;
}
throw new ArgumentNullException(nameof(name));
AssemblyDescriptor rv;
if (!AssemblyNameCache.TryGetValue(name, out rv))
@ -247,9 +231,7 @@ namespace Avalonia.Shared.PlatformSupport
{
// iOS does not support loading assemblies dynamically!
//
#if NETCOREAPP1_0
AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
#elif __IOS__
#if __IOS__
throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
#else
@ -400,5 +382,13 @@ namespace Avalonia.Shared.PlatformSupport
public Dictionary<string, IAssetDescriptor> AvaloniaResources { get; }
public string Name { get; }
}
public static void RegisterResUriParsers()
{
UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoPort | GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoFragment), "avares", -1);
}
}
}

1
src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs

@ -10,6 +10,7 @@ namespace Avalonia.Shared.PlatformSupport
public static void Register(Assembly assembly = null)
{
var standardPlatform = new StandardRuntimePlatform();
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))

Loading…
Cancel
Save