Browse Source

Merge branch 'master' into feature/win32-hide-system-decorations-with-working-frame

pull/2128/head
danwalmsley 7 years ago
committed by GitHub
parent
commit
c6ffd0774e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      Avalonia.sln
  2. 3
      Avalonia.sln.DotSettings
  3. 8
      build/BuildTargets.targets
  4. 22
      packages/Avalonia/Avalonia.csproj
  5. 3
      packages/Avalonia/Avalonia.props
  6. 3
      packages/Avalonia/Avalonia.targets
  7. 3
      packages/Avalonia/AvaloniaBuildTasks.props
  8. 39
      packages/Avalonia/AvaloniaBuildTasks.targets
  9. 10
      samples/ControlCatalog/App.xaml
  10. 8
      samples/ControlCatalog/ControlCatalog.csproj
  11. 6
      samples/ControlCatalog/DecoratedWindow.xaml
  12. 1
      samples/ControlCatalog/MainView.xaml
  13. 6
      samples/ControlCatalog/MainWindow.xaml
  14. 4
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  15. 4
      samples/ControlCatalog/Pages/BorderPage.xaml
  16. 3
      samples/ControlCatalog/Pages/ButtonPage.xaml
  17. 3
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
  18. 3
      samples/ControlCatalog/Pages/CalendarPage.xaml
  19. 4
      samples/ControlCatalog/Pages/CanvasPage.xaml
  20. 10
      samples/ControlCatalog/Pages/CarouselPage.xaml
  21. 3
      samples/ControlCatalog/Pages/CheckBoxPage.xaml
  22. 6
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  23. 3
      samples/ControlCatalog/Pages/DatePickerPage.xaml
  24. 4
      samples/ControlCatalog/Pages/DialogsPage.xaml
  25. 4
      samples/ControlCatalog/Pages/DragAndDropPage.xaml
  26. 4
      samples/ControlCatalog/Pages/DropDownPage.xaml
  27. 4
      samples/ControlCatalog/Pages/ExpanderPage.xaml
  28. 14
      samples/ControlCatalog/Pages/ImagePage.xaml
  29. 5
      samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml
  30. 4
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  31. 6
      samples/ControlCatalog/Pages/MenuPage.xaml
  32. 3
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  33. 6
      samples/ControlCatalog/Pages/ProgressBarPage.xaml
  34. 5
      samples/ControlCatalog/Pages/RadioButtonPage.xaml
  35. 6
      samples/ControlCatalog/Pages/SliderPage.xaml
  36. 9
      samples/ControlCatalog/Pages/TabControlPage.xaml
  37. 4
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  38. 15
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  39. 6
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  40. 6
      samples/ControlCatalog/Pages/TreeViewPage.xaml
  41. 3
      samples/ControlCatalog/Pages/ViewboxPage.xaml
  42. 3
      samples/ControlCatalog/SideBar.xaml
  43. 3
      src/Avalonia.Base/Avalonia.Base.csproj
  44. 2
      src/Avalonia.Base/Platform/IAssetLoader.cs
  45. 64
      src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
  46. 19
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  47. 9
      src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs
  48. 21
      src/Avalonia.Build.Tasks/Extensions.cs
  49. 159
      src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
  50. 20
      src/Avalonia.Build.Tasks/XamlFileInfo.cs
  51. 6
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  52. 2
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  53. 3
      src/Avalonia.Remote.Protocol/DesignMessages.cs
  54. 3
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  55. 22
      src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs
  56. 4
      src/Avalonia.Visuals/Media/PixelSize.cs
  57. 4
      src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs
  58. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  59. 3
      src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
  60. 38
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  61. 25
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaUriTypeConverter.cs
  62. 18
      src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs
  63. 22
      src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs
  64. 12
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaResourceXamlInfo.cs
  65. 207
      src/Shared/PlatformSupport/AssetLoader.cs
  66. 1
      src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs
  67. 48
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  68. 8
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  69. 6
      src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
  70. 19
      src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
  71. 13
      src/Windows/Avalonia.Direct2D1/Utils/DebugUtils.cs
  72. 276
      tests/Avalonia.RenderTests/Media/VisualBrushTests.cs
  73. 8
      tests/Avalonia.RenderTests/TestBase.cs
  74. 5
      tests/Avalonia.UnitTests/MockAssetLoader.cs
  75. BIN
      tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Checkerboard_144_Dpi.expected.png
  76. BIN
      tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Checkerboard_192_Dpi.expected.png
  77. BIN
      tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Checkerboard_96_Dpi.expected.png
  78. BIN
      tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Grip_144_Dpi.expected.png
  79. BIN
      tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Grip_192_Dpi.expected.png
  80. BIN
      tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Grip_96_Dpi.expected.png
  81. BIN
      tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Checkerboard_144_Dpi.expected.png
  82. BIN
      tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Checkerboard_192_Dpi.expected.png
  83. BIN
      tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Checkerboard_96_Dpi.expected.png
  84. BIN
      tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Grip_144_Dpi.expected.png
  85. BIN
      tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Grip_192_Dpi.expected.png
  86. BIN
      tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Grip_96_Dpi.expected.png

27
Avalonia.sln

@ -147,6 +147,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\Splat.props = build\Splat.props
build\System.Memory.props = build\System.Memory.props
build\XUnit.props = build\XUnit.props
build\BuildTargets.targets = build\BuildTargets.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
@ -188,6 +189,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia", "packages\Avalon
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Avalonia.Desktop\Avalonia.Desktop.csproj", "{3C471044-3640-45E3-B1B2-16D2FF8399EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Build.Tasks", "src\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj", "{BF28998D-072C-439A-AFBB-2FE5021241E0}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -1687,6 +1690,30 @@ Global
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhone.Build.0 = Release|Any CPU
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhone.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhone.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.Build.0 = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhone.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhone.Build.0 = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

3
Avalonia.sln.DotSettings

@ -35,4 +35,5 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="s_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

8
build/BuildTargets.targets

@ -0,0 +1,8 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AvaloniaBuildTasksLocation>$(MSBuildThisFileDirectory)\..\src\Avalonia.Build.Tasks\bin\$(Configuration)\netstandard2.0\Avalonia.Build.Tasks.dll</AvaloniaBuildTasksLocation>
<AvaloniaUseExternalMSBuild>true</AvaloniaUseExternalMSBuild>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)\..\packages\Avalonia\AvaloniaBuildTasks.props"/>
<Import Project="$(MSBuildThisFileDirectory)\..\packages\Avalonia\AvaloniaBuildTasks.targets"/>
</Project>

22
packages/Avalonia/Avalonia.csproj

@ -5,6 +5,8 @@
<ItemGroup>
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" EmbedReference="false" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" />
</ItemGroup>
<PropertyGroup>
@ -27,14 +29,22 @@
<Visible>false</Visible>
<BuildAction>None</BuildAction>
</_PackageFiles>
<_PackageFiles Include="Avalonia.props">
<PackagePath>build/Avalonia.props</PackagePath>
<Visible>false</Visible>
<BuildAction>None</BuildAction>
</_PackageFiles>
</ItemGroup>
</Target>
<ItemGroup>
<Content Include="*.props">
<Pack>true</Pack>
<PackagePath>build\</PackagePath>
</Content>
<Content Include="*.targets">
<Pack>true</Pack>
<PackagePath>build\</PackagePath>
</Content>
<Content Include="../../src/Avalonia.Build.Tasks/bin/$(Configuration)/netstandard2.0/Avalonia.Build.Tasks.dll">
<Pack>true</Pack>
<PackagePath>tools\</PackagePath>
</Content>
</ItemGroup>
<Import Project="..\..\build\SharedVersion.props" />
<Import Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\CoreLibraries.props" />

3
packages/Avalonia/Avalonia.props

@ -2,5 +2,8 @@
<PropertyGroup>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\..\tools\netcoreapp2.0\designer\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<AvaloniaPreviewerNetFullToolPath>$(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe</AvaloniaPreviewerNetFullToolPath>
<AvaloniaBuildTasksLocation>$(MSBuildThisFileDirectory)\..\tools\Avalonia.Build.Tasks.dll</AvaloniaBuildTasksLocation>
<AvaloniaUseExternalMSBuild>false</AvaloniaUseExternalMSBuild>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.props"/>
</Project>

3
packages/Avalonia/Avalonia.targets

@ -0,0 +1,3 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildThisFileDirectory)\AvaloniaBuildTasks.targets"/>
</Project>

3
packages/Avalonia/AvaloniaBuildTasks.props

@ -0,0 +1,3 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

39
packages/Avalonia/AvaloniaBuildTasks.targets

@ -0,0 +1,39 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_AvaloniaUseExternalMSBuild>$(AvaloniaUseExternalMSBuild)</_AvaloniaUseExternalMSBuild>
<_AvaloniaUseExternalMSBuild Condition="'$(_AvaloniaForceInternalMSBuild)' == 'true'">false</_AvaloniaUseExternalMSBuild>
</PropertyGroup>
<UsingTask TaskName="GenerateAvaloniaResourcesTask"
AssemblyFile="$(AvaloniaBuildTasksLocation)"
/>
<Target Name="AddAvaloniaResources" BeforeTargets="ResolveReferences">
<PropertyGroup>
<AvaloniaResourcesTemporaryFilePath Condition="'$(AvaloniaResourcesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/resources</AvaloniaResourcesTemporaryFilePath>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="$(AvaloniaResourcesTemporaryFilePath)">
<LogicalName>!AvaloniaResources</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
<Target Name="GenerateAvaloniaResources"
BeforeTargets="CoreCompile;CoreResGen"
Inputs="@(AvaloniaResource);$(MSBuildAllProjects)"
Outputs="$(AvaloniaResourcesTemporaryFilePath)"
DependsOnTargets="$(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences">
<GenerateAvaloniaResourcesTask
Condition="'$(_AvaloniaUseExternalMSBuild)' != 'true'"
Output="$(AvaloniaResourcesTemporaryFilePath)"
Root="$(MSBuildProjectDirectory)"
Resources="@(AvaloniaResource)"
EmbeddedResources="@(EmbeddedResources)"/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration)"/>
</Target>
</Project>

10
samples/ControlCatalog/App.xaml

@ -1,7 +1,9 @@
<Application xmlns="https://github.com/avaloniaui">
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.App">
<Application.Styles>
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
<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"/>
@ -12,6 +14,6 @@
<Style Selector="TextBlock.h3">
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}"/>
</Style>
<StyleInclude Source="resm:ControlCatalog.SideBar.xaml"/>
<StyleInclude Source="/SideBar.xaml"/>
</Application.Styles>
</Application>

8
samples/ControlCatalog/ControlCatalog.csproj

@ -6,10 +6,11 @@
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml">
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Assets\*" />
</AvaloniaResource>
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\Fonts\SourceSansPro-Bold.ttf" />
@ -24,4 +25,5 @@
</ItemGroup>
<Import Project="..\..\build\Serilog.props" />
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

6
samples/ControlCatalog/DecoratedWindow.xaml

@ -1,6 +1,8 @@
<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.DecoratedWindow"
Title="Avalonia Control Gallery"
Icon="resm:ControlCatalog.Assets.test_icon.ico"
Icon="/Assets/test_icon.ico"
xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False">
<Grid RowDefinitions="5,*,5" ColumnDefinitions="5,*,5">
<DockPanel Grid.Column="1" Grid.Row="1" >
@ -30,4 +32,4 @@
<Border Name="Bottom" Background="Blue" Grid.Row="2" Grid.Column="1" />
<Border Name="Left" Background="Blue" Grid.Row="1" />
</Grid>
</Window>
</Window>

1
samples/ControlCatalog/MainView.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:pages="clr-namespace:ControlCatalog.Pages"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.MainView"
Background="{DynamicResource ThemeBackgroundBrush}"
Foreground="{DynamicResource ThemeForegroundBrush}"
FontSize="{DynamicResource FontSizeNormal}">

6
samples/ControlCatalog/MainWindow.xaml

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

4
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.AutoCompleteBoxPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">AutoCompleteBox</TextBlock>
<TextBlock Classes="h2">A control into which the user can input text</TextBlock>

4
samples/ControlCatalog/Pages/BorderPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.BorderPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Border</TextBlock>
<TextBlock Classes="h2">A control which decorates a child with a border and background</TextBlock>

3
samples/ControlCatalog/Pages/ButtonPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ButtonPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Button</TextBlock>
<TextBlock Classes="h2">A button control</TextBlock>

3
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ButtonSpinnerPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ButtonSpinner</TextBlock>

3
samples/ControlCatalog/Pages/CalendarPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CalendarPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Calendar</TextBlock>
<TextBlock Classes="h2">A calendar control for selecting dates</TextBlock>

4
samples/ControlCatalog/Pages/CanvasPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CanvasPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Canvas</TextBlock>
<TextBlock Classes="h2">A panel which lays out its children by explicit coordinates</TextBlock>

10
samples/ControlCatalog/Pages/CarouselPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CarouselPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Carousel</TextBlock>
<TextBlock Classes="h2">An items control that displays its items as pages that fill the control.</TextBlock>
@ -11,9 +13,9 @@
<Carousel.PageTransition>
<PageSlide Duration="0.25" Orientation="Vertical" />
</Carousel.PageTransition>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"/>
<Image Source="resm:ControlCatalog.Assets.hirsch-899118_640.jpg"/>
<Image Source="resm:ControlCatalog.Assets.maple-leaf-888807_640.jpg"/>
<Image Source="/Assets/delicate-arch-896885_640.jpg"/>
<Image Source="/Assets/hirsch-899118_640.jpg"/>
<Image Source="/Assets/maple-leaf-888807_640.jpg"/>
</Carousel>
<Button Name="right" VerticalAlignment="Center" Padding="20">
<Path Data="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" Fill="Black"/>

3
samples/ControlCatalog/Pages/CheckBoxPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.CheckBoxPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">CheckBox</TextBlock>
<TextBlock Classes="h2">A check box control</TextBlock>

6
samples/ControlCatalog/Pages/ContextMenuPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ContextMenuPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Context Menu</TextBlock>
<TextBlock Classes="h2">A right click menu that can be applied to any control.</TextBlock>
@ -19,7 +21,7 @@
</MenuItem>
<MenuItem Header="Menu Item with _Icon">
<MenuItem.Icon>
<Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
<Image Source="/Assets/github_icon.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu Item with _Checkbox">

3
samples/ControlCatalog/Pages/DatePickerPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DatePickerPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">DatePicker</TextBlock>
<TextBlock Classes="h2">A control for selecting dates with a calendar drop-down</TextBlock>

4
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DialogsPage">
<StackPanel Orientation="Vertical" Spacing="4" Margin="4">
<Button Name="OpenFile">Open File</Button>
<Button Name="SaveFile">Save File</Button>

4
samples/ControlCatalog/Pages/DragAndDropPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DragAndDropPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Drag+Drop</TextBlock>
<TextBlock Classes="h2">Example of Drag+Drop capabilities</TextBlock>

4
samples/ControlCatalog/Pages/DropDownPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DropDownPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">DropDown</TextBlock>
<TextBlock Classes="h2">A drop-down list.</TextBlock>

4
samples/ControlCatalog/Pages/ExpanderPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ExpanderPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Expander</TextBlock>
<TextBlock Classes="h2">Expands to show nested content</TextBlock>

14
samples/ControlCatalog/Pages/ImagePage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ImagePage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Image</TextBlock>
<TextBlock Classes="h2">Displays an image</TextBlock>
@ -9,28 +11,28 @@
Spacing="16">
<StackPanel Orientation="Vertical">
<TextBlock>No Stretch</TextBlock>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
<Image Source="/Assets/delicate-arch-896885_640.jpg"
Width="100" Height="200"
Stretch="None"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Fill</TextBlock>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
<Image Source="/Assets/delicate-arch-896885_640.jpg"
Width="100" Height="200"
Stretch="Fill"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Uniform</TextBlock>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
<Image Source="/Assets/delicate-arch-896885_640.jpg"
Width="100" Height="200"
Stretch="Uniform"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>UniformToFill</TextBlock>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"
<Image Source="/Assets/delicate-arch-896885_640.jpg"
Width="100" Height="200"
Stretch="UniformToFill"/>
</StackPanel>
@ -40,4 +42,4 @@
<Image Name="Icon" Width="100" Height="200" Stretch="None" />
</StackPanel>
</StackPanel>
</UserControl>
</UserControl>

5
samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.LayoutTransformControlPage">
<DockPanel>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto" Margin="16" DockPanel.Dock="Top">
<TextBlock Grid.Column="0" Grid.Row="0">Rotation</TextBlock>
@ -23,4 +24,4 @@
</LayoutTransformControl>
</Grid>
</DockPanel>
</UserControl>
</UserControl>

4
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ListBoxPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ListBox</TextBlock>
<TextBlock Classes="h2">Hosts a collection of ListBoxItem.</TextBlock>

6
samples/ControlCatalog/Pages/MenuPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.MenuPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Menu</TextBlock>
<TextBlock Classes="h2">A window menu</TextBlock>
@ -19,7 +21,7 @@
</MenuItem>
<MenuItem Header="Menu Item with _Icon">
<MenuItem.Icon>
<Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
<Image Source="/Assets/github_icon.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu Item with _Checkbox">

3
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.NumericUpDownPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Margin="2" Classes="h1">Numeric up-down control</TextBlock>
<TextBlock Margin="2" Classes="h2" TextWrapping="Wrap">Numeric up-down control provides a TextBox with button spinners that allow incrementing and decrementing numeric values by using the spinner buttons, keyboard up/down arrows, or mouse wheel.</TextBlock>

6
samples/ControlCatalog/Pages/ProgressBarPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ProgressBarPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ProgressBar</TextBlock>
<TextBlock Classes="h2">A progress bar control</TextBlock>
@ -21,4 +23,4 @@
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>
</UserControl>

5
samples/ControlCatalog/Pages/RadioButtonPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.RadioButtonPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">RadioButton</TextBlock>
<TextBlock Classes="h2">Allows the selection of a single option of many</TextBlock>
@ -37,4 +38,4 @@
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>
</UserControl>

6
samples/ControlCatalog/Pages/SliderPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.SliderPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Slider</TextBlock>
<TextBlock Classes="h2">A control that lets the user select from a range of values by moving a Thumb control along a Track.</TextBlock>
@ -18,4 +20,4 @@
</StackPanel>
</StackPanel>
</UserControl>
</UserControl>

9
samples/ControlCatalog/Pages/TabControlPage.xaml

@ -1,4 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.TabControlPage"
xmlns="https://github.com/avaloniaui">
<DockPanel>
<TextBlock
DockPanel.Dock="Top"
@ -29,13 +32,13 @@
<TabItem Header="Arch">
<StackPanel Orientation="Vertical" Spacing="8">
<TextBlock>This is the first page in the TabControl.</TextBlock>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg" Width="300"/>
<Image Source="/Assets/delicate-arch-896885_640.jpg" Width="300"/>
</StackPanel>
</TabItem>
<TabItem Header="Leaf">
<StackPanel Orientation="Vertical" Spacing="8">
<TextBlock>This is the second page in the TabControl.</TextBlock>
<Image Source="resm:ControlCatalog.Assets.maple-leaf-888807_640.jpg" Width="300"/>
<Image Source="/Assets/maple-leaf-888807_640.jpg" Width="300"/>
</StackPanel>
</TabItem>
<TabItem Header="Disabled" IsEnabled="False">

4
samples/ControlCatalog/Pages/TabControlPage.xaml.cs

@ -26,13 +26,13 @@ namespace ControlCatalog.Pages
{
Header = "Arch",
Text = "This is the first templated tab page.",
Image = LoadBitmap("resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg?assembly=ControlCatalog"),
Image = LoadBitmap("avares://ControlCatalog/Assets/delicate-arch-896885_640.jpg"),
},
new TabItemViewModel
{
Header = "Leaf",
Text = "This is the second templated tab page.",
Image = LoadBitmap("resm:ControlCatalog.Assets.maple-leaf-888807_640.jpg?assembly=ControlCatalog"),
Image = LoadBitmap("avares://ControlCatalog/Assets/maple-leaf-888807_640.jpg"),
},
new TabItemViewModel
{

15
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.TextBoxPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">TextBox</TextBlock>
<TextBlock Classes="h2">A control into which the user can input text</TextBlock>
@ -33,11 +35,20 @@
Text="Multiline TextBox with no TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
</StackPanel>
<StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Classes="h2">resm fonts</TextBlock>
<TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-Italic.ttf?assembly=ControlCatalog#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-*.ttf?assembly=ControlCatalog#Source Sans Pro"/>
</StackPanel>
<StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Classes="h2">res fonts</TextBlock>
<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>
</UserControl>
</UserControl>

6
samples/ControlCatalog/Pages/ToolTipPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ToolTipPage">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Classes="h1">ToolTip</TextBlock>
@ -38,4 +40,4 @@
</Border>
</Grid>
</StackPanel>
</UserControl>
</UserControl>

6
samples/ControlCatalog/Pages/TreeViewPage.xaml

@ -1,4 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui">
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.TreeViewPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">TreeView</TextBlock>
<TextBlock Classes="h2">Displays a hierachical tree of data.</TextBlock>
@ -16,4 +18,4 @@
</TreeView>
</StackPanel>
</StackPanel>
</UserControl>
</UserControl>

3
samples/ControlCatalog/Pages/ViewboxPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ViewboxPage">
<UserControl.Resources>
<StreamGeometry x:Key="Acorn">
F1 M 16.6309,18.6563C 17.1309,

3
samples/ControlCatalog/SideBar.xaml

@ -1,5 +1,6 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.SideBar">
<Style Selector="TabControl.sidebar">
<Setter Property="TabStripPlacement" Value="Left"/>
<Setter Property="Padding" Value="8 0 0 0"/>

3
src/Avalonia.Base/Avalonia.Base.csproj

@ -6,6 +6,9 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj"/>
</ItemGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\Binding.props" />
<Import Project="..\..\build\Rx.props" />

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

@ -66,6 +66,6 @@ namespace Avalonia.Platform
/// </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>
IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri uri);
IEnumerable<Uri> GetAssets(Uri uri, Uri baseUri);
}
}

64
src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
// ReSharper disable AssignNullToNotNullAttribute
namespace Avalonia.Utilities
{
#if !BUILDTASK
public
#endif
static class AvaloniaResourcesIndexReaderWriter
{
private const int LastKnownVersion = 1;
public static List<AvaloniaResourcesIndexEntry> Read(Stream stream)
{
var ver = new BinaryReader(stream).ReadInt32();
if (ver > LastKnownVersion)
throw new Exception("Resources index format version is not known");
var index = (AvaloniaResourcesIndex)
new DataContractSerializer(typeof(AvaloniaResourcesIndex)).ReadObject(stream);
return index.Entries;
}
public static void Write(Stream stream, List<AvaloniaResourcesIndexEntry> entries)
{
new BinaryWriter(stream).Write(LastKnownVersion);
new DataContractSerializer(typeof(AvaloniaResourcesIndex)).WriteObject(stream,
new AvaloniaResourcesIndex()
{
Entries = entries
});
}
}
[DataContract]
#if !BUILDTASK
public
#endif
class AvaloniaResourcesIndex
{
[DataMember]
public List<AvaloniaResourcesIndexEntry> Entries { get; set; } = new List<AvaloniaResourcesIndexEntry>();
}
[DataContract]
#if !BUILDTASK
public
#endif
class AvaloniaResourcesIndexEntry
{
[DataMember]
public string Path { get; set; }
[DataMember]
public int Offset { get; set; }
[DataMember]
public int Size { get; set; }
}
}

19
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
<DefineConstants>$(DefineConstants);BUILDTASK</DefineConstants>
<Packable>false</Packable>
</PropertyGroup>
<ItemGroup>
<Compile Include="../Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs">
<Link>Shared/AvaloniaResourcesIndex.cs</Link>
</Compile>
<Compile Include="../Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaResourceXamlInfo.cs">
<Link>Shared/AvaloniaResourceXamlInfo.cs</Link>
</Compile>
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" />
</ItemGroup>
</Project>

9
src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs

@ -0,0 +1,9 @@
namespace Avalonia.Build.Tasks
{
public enum BuildEngineErrorCode
{
InvalidXAML = 1,
DuplicateXClass = 2,
LegacyResmScheme = 3,
}
}

21
src/Avalonia.Build.Tasks/Extensions.cs

@ -0,0 +1,21 @@
using Microsoft.Build.Framework;
namespace Avalonia.Build.Tasks
{
public static class Extensions
{
static string FormatErrorCode(BuildEngineErrorCode code) => $"AVLN:{(int)code:0000}";
public static void LogError(this IBuildEngine engine, BuildEngineErrorCode code, string file, string message)
{
engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", FormatErrorCode(code), file ?? "", 0, 0, 0, 0, message,
"", "Avalonia"));
}
public static void LogWarning(this IBuildEngine engine, BuildEngineErrorCode code, string file, string message)
{
engine.LogWarningEvent(new BuildWarningEventArgs("Avalonia", FormatErrorCode(code), file ?? "", 0, 0, 0, 0, message,
"", "Avalonia"));
}
}
}

159
src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs

@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using Avalonia.Markup.Xaml.PortableXaml;
using Avalonia.Utilities;
using Microsoft.Build.Framework;
using SPath=System.IO.Path;
namespace Avalonia.Build.Tasks
{
public class GenerateAvaloniaResourcesTask : ITask
{
[Required]
public ITaskItem[] Resources { get; set; }
[Required]
public string Root { get; set; }
[Required]
public string Output { get; set; }
[Required]
public ITaskItem[] EmbeddedResources { get; set; }
class Source
{
public string Path { get; set; }
public int Size { get; set; }
private byte[] _data;
private string _sourcePath;
public Source(string file, string root)
{
file = SPath.GetFullPath(file);
root = SPath.GetFullPath(root);
var fileUri = new Uri(file, UriKind.Absolute);
var rootUri = new Uri(root, UriKind.Absolute);
rootUri = new Uri(rootUri.ToString().TrimEnd('/') + '/');
Path = '/' + rootUri.MakeRelativeUri(fileUri).ToString().TrimStart('/');
_sourcePath = file;
Size = (int)new FileInfo(_sourcePath).Length;
}
public string SystemPath => _sourcePath ?? Path;
public Source(string path, byte[] data)
{
Path = path;
_data = data;
Size = data.Length;
}
public Stream Open()
{
if (_data != null)
return new MemoryStream(_data, false);
return File.OpenRead(_sourcePath);
}
public string ReadAsString()
{
if (_data != null)
return Encoding.UTF8.GetString(_data);
return File.ReadAllText(_sourcePath);
}
}
List<Source> BuildResourceSources() => Resources.Select(r => new Source(r.ItemSpec, Root)).ToList();
private void Pack(Stream output, List<Source> sources)
{
var offsets = new Dictionary<Source, int>();
var coffset = 0;
foreach (var s in sources)
{
offsets[s] = coffset;
coffset += s.Size;
}
var index = sources.Select(s => new AvaloniaResourcesIndexEntry
{
Path = s.Path,
Size = s.Size,
Offset = offsets[s]
}).ToList();
var ms = new MemoryStream();
AvaloniaResourcesIndexReaderWriter.Write(ms, index);
new BinaryWriter(output).Write((int)ms.Length);
ms.Position = 0;
ms.CopyTo(output);
foreach (var s in sources)
{
using(var input = s.Open())
input.CopyTo(output);
}
}
private bool PreProcessXamlFiles(List<Source> sources)
{
var typeToXamlIndex = new Dictionary<string, string>();
foreach (var s in sources.ToList())
{
if (s.Path.ToLowerInvariant().EndsWith(".xaml") || s.Path.ToLowerInvariant().EndsWith(".paml"))
{
XamlFileInfo info;
try
{
info = XamlFileInfo.Parse(s.ReadAsString());
}
catch(Exception e)
{
BuildEngine.LogError(BuildEngineErrorCode.InvalidXAML, s.SystemPath, "File doesn't contain valid XAML: " + e);
return false;
}
if (info.XClass != null)
{
if (typeToXamlIndex.ContainsKey(info.XClass))
{
BuildEngine.LogError(BuildEngineErrorCode.DuplicateXClass, s.SystemPath,
$"Duplicate x:Class directive, {info.XClass} is already used in {typeToXamlIndex[info.XClass]}");
return false;
}
typeToXamlIndex[info.XClass] = s.Path;
}
}
}
var xamlInfo = new AvaloniaResourceXamlInfo
{
ClassToResourcePathIndex = typeToXamlIndex
};
var ms = new MemoryStream();
new DataContractSerializer(typeof(AvaloniaResourceXamlInfo)).WriteObject(ms, xamlInfo);
sources.Add(new Source("/!AvaloniaResourceXamlInfo", ms.ToArray()));
return true;
}
public bool Execute()
{
foreach(var r in EmbeddedResources.Where(r=>r.ItemSpec.EndsWith(".xaml")||r.ItemSpec.EndsWith(".paml")))
BuildEngine.LogWarning(BuildEngineErrorCode.LegacyResmScheme, r.ItemSpec,
"XAML file is packed using legacy EmbeddedResource/resm scheme, relative URIs won't work");
var resources = BuildResourceSources();
if (!PreProcessXamlFiles(resources))
return false;
var dir = Path.GetDirectoryName(Output);
Directory.CreateDirectory(dir);
using (var file = File.Create(Output))
Pack(file, resources);
return true;
}
public IBuildEngine BuildEngine { get; set; }
public ITaskHost HostObject { get; set; }
}
}

20
src/Avalonia.Build.Tasks/XamlFileInfo.cs

@ -0,0 +1,20 @@
using System.Xml.Linq;
namespace Avalonia.Build.Tasks
{
public class XamlFileInfo
{
public string XClass { get; set; }
public static XamlFileInfo Parse(string data)
{
var xdoc = XDocument.Parse(data);
var xclass = xdoc.Root.Attribute(XName.Get("Class", "http://schemas.microsoft.com/winfx/2006/xaml"));
return new XamlFileInfo
{
XClass = xclass?.Value
};
}
}
}

6
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@ -12,7 +12,7 @@ namespace Avalonia.DesignerSupport
{
public class DesignWindowLoader
{
public static Window LoadDesignerWindow(string xaml, string assemblyPath)
public static Window LoadDesignerWindow(string xaml, string assemblyPath, string xamlFileProjectPath)
{
Window window;
Control control;
@ -26,9 +26,11 @@ namespace Avalonia.DesignerSupport
Uri baseUri = null;
if (assemblyPath != null)
{
if (xamlFileProjectPath == null)
xamlFileProjectPath = "/Designer/Fake.xaml";
//Fabricate fake Uri
baseUri =
new Uri("resm:Fake.xaml?assembly=" + Path.GetFileNameWithoutExtension(assemblyPath));
new Uri($"avares://{Path.GetFileNameWithoutExtension(assemblyPath)}{xamlFileProjectPath}");
}
var localAsm = assemblyPath != null ? Assembly.LoadFile(Path.GetFullPath(assemblyPath)) : null;

2
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@ -199,7 +199,7 @@ namespace Avalonia.DesignerSupport.Remote
s_currentWindow = null;
try
{
s_currentWindow = DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath);
s_currentWindow = DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath, xaml.XamlFileProjectPath);
s_transport.Send(new UpdateXamlResultMessage(){Handle = s_currentWindow.PlatformImpl?.Handle?.Handle.ToString()});
}
catch (Exception e)

3
src/Avalonia.Remote.Protocol/DesignMessages.cs

@ -7,6 +7,7 @@ namespace Avalonia.Remote.Protocol.Designer
{
public string Xaml { get; set; }
public string AssemblyPath { get; set; }
public string XamlFileProjectPath { get; set; }
}
[AvaloniaRemoteMessageGuid("B7A70093-0C5D-47FD-9261-22086D43A2E2")]
@ -22,4 +23,4 @@ namespace Avalonia.Remote.Protocol.Designer
public string SessionId { get; set; }
}
}
}

3
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@ -13,7 +13,10 @@
<ProjectReference Include="..\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
<AvaloniaResource Include="DefaultTheme.xaml"/>
<AvaloniaResource Include="Accents/*.xaml"/>
</ItemGroup>
<Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\BuildTargets.targets"/>
<Import Project="..\..\build\Rx.props" />
</Project>

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

@ -32,11 +32,11 @@ namespace Avalonia.Media.Fonts
/// <returns></returns>
private static IEnumerable<Uri> GetFontAssetsByLocation(Uri location)
{
var availableAssets = s_assetLoader.GetAssets(location);
var availableAssets = s_assetLoader.GetAssets(location, null);
var matchingAssets = availableAssets.Where(x => x.absolutePath.EndsWith(".ttf") || x.absolutePath.EndsWith(".otf"));
var matchingAssets = availableAssets.Where(x => x.AbsolutePath.EndsWith(".ttf") || x.AbsolutePath.EndsWith(".otf"));
return matchingAssets.Select(x => GetAssetUri(x.absolutePath, x.assembly));
return matchingAssets;
}
/// <summary>
@ -48,25 +48,15 @@ namespace Avalonia.Media.Fonts
/// <returns></returns>
private static IEnumerable<Uri> GetFontAssetsByFileName(Uri location, string fileName)
{
var availableResources = s_assetLoader.GetAssets(location);
var availableResources = s_assetLoader.GetAssets(location, null);
var compareTo = location.AbsolutePath + "." + fileName.Split('*').First();
var matchingResources =
availableResources.Where(x => x.absolutePath.Contains(compareTo) && (x.absolutePath.EndsWith(".ttf") || x.absolutePath.EndsWith(".otf")));
availableResources.Where(x => x.AbsolutePath.Contains(compareTo) && (x.AbsolutePath.EndsWith(".ttf") || x.AbsolutePath.EndsWith(".otf")));
return matchingResources.Select(x => GetAssetUri(x.absolutePath, x.assembly));
return matchingResources;
}
/// <summary>
/// Returns a <see cref="Uri"/> for a font asset that follows the resm scheme
/// </summary>
/// <param name="absolutePath"></param>
/// <param name="assembly"></param>
/// <returns></returns>
private static Uri GetAssetUri(string absolutePath, Assembly assembly)
{
return new Uri("resm:" + absolutePath + "?assembly=" + assembly.GetName().Name, UriKind.RelativeOrAbsolute);
}
}
}

4
src/Avalonia.Visuals/Media/PixelSize.cs

@ -159,8 +159,8 @@ namespace Avalonia
/// <param name="dpi">The dots per inch.</param>
/// <returns>The device-independent size.</returns>
public static PixelSize FromSize(Size size, Vector dpi) => new PixelSize(
(int)(size.Width * (dpi.X / 96)),
(int)(size.Height * (dpi.Y / 96)));
(int)Math.Ceiling(size.Width * (dpi.X / 96)),
(int)Math.Ceiling(size.Height * (dpi.Y / 96)));
/// <summary>
/// Returns the string representation of the size.

4
src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs

@ -116,8 +116,8 @@ namespace Avalonia.Rendering.Utilities
return true;
if (SourceRect.Size.AspectRatio == _imageSize.AspectRatio)
return false;
if ((int)SourceRect.Width != _imageSize.Width ||
(int)SourceRect.Height != _imageSize.Height)
if (SourceRect.Width != _imageSize.Width ||
SourceRect.Height != _imageSize.Height)
return true;
return false;
}

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -9,6 +9,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="AvaloniaXamlLoader.cs" />
<Compile Include="Converters\AvaloniaUriTypeConverter.cs" />
<Compile Include="Converters\MemberSelectorTypeConverter.cs" />
<Compile Include="Converters\ParseTypeConverter.cs" />
<Compile Include="Converters\SetterValueTypeConverter.cs" />
@ -18,6 +19,7 @@
<Compile Include="MarkupExtensions\StaticResourceExtension.cs" />
<Compile Include="MarkupExtensions\StyleIncludeExtension.cs" />
<Compile Include="Parsers\PropertyParser.cs" />
<Compile Include="PortableXaml\AvaloniaResourceXamlInfo.cs" />
<Compile Include="PortableXaml\AvaloniaXamlContext.cs" />
<Compile Include="PortableXaml\AttributeExtensions.cs" />
<Compile Include="PortableXaml\AvaloniaMemberAttributeProvider.cs" />

3
src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs

@ -37,7 +37,8 @@ namespace Avalonia.Markup.Xaml
{ typeof(Selector), typeof(SelectorTypeConverter) },
{ typeof(TimeSpan), typeof(TimeSpanTypeConverter) },
{ typeof(WindowIcon), typeof(IconTypeConverter) },
{ typeof(CultureInfo), typeof(CultureInfoConverter)}
{ typeof(CultureInfo), typeof(CultureInfoConverter)},
{ typeof(Uri), typeof(AvaloniaUriTypeConverter)}
};
/// <summary>

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

@ -10,6 +10,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
namespace Avalonia.Markup.Xaml
@ -85,7 +87,7 @@ namespace Avalonia.Markup.Xaml
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
}
foreach (var uri in GetUrisFor(type))
foreach (var uri in GetUrisFor(assetLocator, type))
{
if (assetLocator.Exists(uri))
{
@ -134,18 +136,14 @@ namespace Avalonia.Markup.Xaml
var asset = assetLocator.OpenAndGetAssembly(uri, baseUri);
using (var stream = asset.stream)
{
var absoluteUri = uri.IsAbsoluteUri ? uri : new Uri(baseUri, uri);
try
{
return Load(stream, asset.assembly, rootInstance, uri);
return Load(stream, asset.assembly, rootInstance, absoluteUri);
}
catch (Exception e)
{
var uriString = uri.ToString();
if (!uri.IsAbsoluteUri)
{
uriString = new Uri(baseUri, uri).AbsoluteUri;
}
throw new XamlLoadException("Error loading xaml at " + uriString + ": " + e.Message, e);
throw new XamlLoadException("Error loading xaml at " + absoluteUri + ": " + e.Message, e);
}
}
}
@ -221,15 +219,37 @@ namespace Avalonia.Markup.Xaml
return LoadFromReader(reader, null);
}
private static readonly DataContractSerializer s_xamlInfoSerializer =
new DataContractSerializer(typeof(AvaloniaResourceXamlInfo));
/// <summary>
/// Gets the URI for a type.
/// </summary>
/// <param name="assetLocator"></param>
/// <param name="type">The type.</param>
/// <returns>The URI.</returns>
private static IEnumerable<Uri> GetUrisFor(Type type)
private static IEnumerable<Uri> GetUrisFor(IAssetLoader assetLocator, Type type)
{
var asm = type.GetTypeInfo().Assembly.GetName().Name;
var xamlInfoUri = new Uri($"avares://{asm}/!AvaloniaResourceXamlInfo");
var typeName = type.FullName;
if (typeName == null)
throw new ArgumentException("Type doesn't have a FullName");
if (assetLocator.Exists(xamlInfoUri))
{
using (var xamlInfoStream = assetLocator.Open(xamlInfoUri))
{
var xamlInfo = (AvaloniaResourceXamlInfo)s_xamlInfoSerializer.ReadObject(xamlInfoStream);
if (xamlInfo.ClassToResourcePathIndex.TryGetValue(typeName, out var rv) == true)
{
yield return new Uri($"avares://{asm}{rv}");
yield break;
}
}
}
yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm);
yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm);
}

25
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaUriTypeConverter.cs

@ -0,0 +1,25 @@
using System;
using System.ComponentModel;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
public class AvaloniaUriTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var s = value as string;
if (s == null)
return null;
//On Unix Uri tries to interpret paths starting with "/" as file Uris
if (s.StartsWith("/"))
return new Uri(s, UriKind.Relative);
return new Uri(s);
}
}
}

18
src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs

@ -20,18 +20,16 @@ namespace Avalonia.Markup.Xaml.Converters
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var uri = new Uri((string)value, UriKind.RelativeOrAbsolute);
var scheme = uri.IsAbsoluteUri ? uri.Scheme : "file";
var s = (string)value;
var uri = s.StartsWith("/")
? new Uri(s, UriKind.Relative)
: new Uri(s, UriKind.RelativeOrAbsolute);
switch (scheme)
{
case "file":
return new Bitmap((string)value);
if(uri.IsAbsoluteUri && uri.IsFile)
return new Bitmap(uri.LocalPath);
default:
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
return new Bitmap(assets.Open(uri, context.GetBaseUri()));
}
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
return new Bitmap(assets.Open(uri, context.GetBaseUri()));
}
}
}

22
src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs

@ -36,20 +36,16 @@ namespace Avalonia.Markup.Xaml.Converters
throw new NotSupportedException();
}
private WindowIcon CreateIconFromPath(ITypeDescriptorContext context, string path)
private WindowIcon CreateIconFromPath(ITypeDescriptorContext context, string s)
{
var uri = new Uri(path, UriKind.RelativeOrAbsolute);
var scheme = uri.IsAbsoluteUri ? uri.Scheme : "file";
switch (scheme)
{
case "file":
return new WindowIcon(path);
default:
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
return new WindowIcon(assets.Open(uri, context.GetBaseUri()));
}
var uri = s.StartsWith("/")
? new Uri(s, UriKind.Relative)
: new Uri(s, UriKind.RelativeOrAbsolute);
if(uri.IsAbsoluteUri && uri.IsFile)
return new WindowIcon(uri.LocalPath);
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
return new WindowIcon(assets.Open(uri, context.GetBaseUri()));
}
}
}

12
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaResourceXamlInfo.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Avalonia.Markup.Xaml.PortableXaml
{
[DataContract]
class AvaloniaResourceXamlInfo
{
[DataMember]
public Dictionary<string, string> ClassToResourcePathIndex { get; set; } = new Dictionary<string, string>();
}
}

207
src/Shared/PlatformSupport/AssetLoader.cs

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using Avalonia.Platform;
using Avalonia.Utilities;
namespace Avalonia.Shared.PlatformSupport
{
@ -15,23 +16,24 @@ namespace Avalonia.Shared.PlatformSupport
/// </summary>
public class AssetLoader : IAssetLoader
{
private const string AvaloniaResourceName = "!AvaloniaResources";
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>
@ -40,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>
@ -99,21 +101,59 @@ namespace Avalonia.Shared.PlatformSupport
/// Gets all assets of a folder and subfolders that match specified uri.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">Base URI that is used if <paramref name="uri"/> is relative.</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)
public IEnumerable<Uri> GetAssets(Uri uri, Uri baseUri)
{
var assembly = GetAssembly(uri);
if (uri.IsAbsoluteUri && uri.Scheme == "resm")
{
var assembly = GetAssembly(uri);
return assembly?.Resources.Where(x => x.Key.Contains(uri.AbsolutePath))
.Select(x =>new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ??
Enumerable.Empty<Uri>();
}
return assembly?.Resources.Where(x => x.Key.Contains(uri.AbsolutePath))
.Select(x => (x.Key, x.Value.Assembly)) ??
Enumerable.Empty<(string AbsolutePath, Assembly Assembly)>();
uri = EnsureAbsolute(uri, baseUri);
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 Enumerable.Empty<Uri>();
path = path.TrimEnd('/') + '/';
return asm.AvaloniaResources.Where(r => r.Key.StartsWith(path))
.Select(x => new Uri($"avares://{asm.Name}{x.Key}"));
}
return Enumerable.Empty<Uri>();
}
private IAssetDescriptor GetAsset(Uri uri, Uri baseUri)
private Uri EnsureAbsolute(Uri uri, Uri baseUri)
{
if (!uri.IsAbsoluteUri || uri.Scheme == "resm")
if (uri.IsAbsoluteUri)
return uri;
if(baseUri == null)
throw new ArgumentException($"Relative uri {uri} without base url");
if (!baseUri.IsAbsoluteUri)
throw new ArgumentException($"Base uri {baseUri} is relative");
if (baseUri.Scheme == "resm")
throw new ArgumentException(
$"Relative uris for 'resm' scheme aren't supported; {baseUri} uses resm");
return new Uri(baseUri, uri);
}
private IAssetDescriptor GetAsset(Uri uri, Uri baseUri)
{
if (uri.IsAbsoluteUri && uri.Scheme == "resm")
{
var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultAssembly;
var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultResmAssembly;
if (asm == null)
{
@ -128,19 +168,45 @@ namespace Avalonia.Shared.PlatformSupport
asm.Resources.TryGetValue(resourceKey, out rv);
return rv;
}
throw new ArgumentException($"Invalid uri, see https://github.com/AvaloniaUI/Avalonia/issues/282#issuecomment-166982104", nameof(uri));
uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "avares")
{
var (asm, path) = GetResAsmAndPath(uri);
if (asm.AvaloniaResources == null)
return null;
asm.AvaloniaResources.TryGetValue(path, out var desc);
return desc;
}
throw new ArgumentException($"Unsupported url type: " + uri.Scheme, nameof(uri));
}
private (AssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri)
{
var asm = GetAssembly(uri.Authority);
return (asm, uri.AbsolutePath);
}
private AssemblyDescriptor GetAssembly(Uri uri)
{
if (uri != null)
{
var qs = ParseQueryString(uri);
string assemblyName;
if (!uri.IsAbsoluteUri)
return null;
if (uri.Scheme == "avares")
return GetResAsmAndPath(uri).asm;
if (qs.TryGetValue("assembly", out assemblyName))
if (uri.Scheme == "resm")
{
return GetAssembly(assemblyName);
var qs = ParseQueryString(uri);
string assemblyName;
if (qs.TryGetValue("assembly", out assemblyName))
{
return GetAssembly(assemblyName);
}
}
}
@ -150,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))
@ -167,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
@ -213,6 +275,80 @@ namespace Avalonia.Shared.PlatformSupport
public Assembly Assembly => _asm;
}
private class AvaloniaResourceDescriptor : IAssetDescriptor
{
private readonly int _offset;
private readonly int _length;
public Assembly Assembly { get; }
public AvaloniaResourceDescriptor(Assembly asm, int offset, int length)
{
_offset = offset;
_length = length;
Assembly = asm;
}
public Stream GetStream()
{
return new SlicedStream(Assembly.GetManifestResourceStream(AvaloniaResourceName), _offset, _length);
}
}
class SlicedStream : Stream
{
private readonly Stream _baseStream;
private readonly int _from;
public SlicedStream(Stream baseStream, int from, int length)
{
Length = length;
_baseStream = baseStream;
_from = from;
_baseStream.Position = from;
}
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - Position));
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin == SeekOrigin.Begin)
Position = offset;
if (origin == SeekOrigin.End)
Position = _from + Length + offset;
if (origin == SeekOrigin.Current)
Position = Position + offset;
return Position;
}
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override bool CanRead => true;
public override bool CanSeek => _baseStream.CanRead;
public override bool CanWrite => false;
public override long Length { get; }
public override long Position
{
get => _baseStream.Position - _from;
set => _baseStream.Position = value + _from;
}
protected override void Dispose(bool disposing)
{
if (disposing)
_baseStream.Dispose();
}
public override void Close() => _baseStream.Close();
}
private class AssemblyDescriptor
{
@ -225,12 +361,37 @@ namespace Avalonia.Shared.PlatformSupport
Resources = assembly.GetManifestResourceNames()
.ToDictionary(n => n, n => (IAssetDescriptor)new AssemblyResourceDescriptor(assembly, n));
Name = assembly.GetName().Name;
using (var resources = assembly.GetManifestResourceStream(AvaloniaResourceName))
{
if (resources != null)
{
Resources.Remove(AvaloniaResourceName);
var indexLength = new BinaryReader(resources).ReadInt32();
var index = AvaloniaResourcesIndexReaderWriter.Read(new SlicedStream(resources, 4, indexLength));
var baseOffset = indexLength + 4;
AvaloniaResources = index.ToDictionary(r => "/" + r.Path.TrimStart('/'), r => (IAssetDescriptor)
new AvaloniaResourceDescriptor(assembly, baseOffset + r.Offset, r.Size));
}
}
}
}
public Assembly Assembly { get; }
public Dictionary<string, IAssetDescriptor> Resources { get; }
public Dictionary<string, IAssetDescriptor> AvaloniaResources { get; }
public string Name { get; }
}
public static void RegisterResUriParsers()
{
if (!UriParser.IsKnownScheme("avares"))
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))

48
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -225,10 +225,7 @@ namespace Avalonia.Skia
/// <inheritdoc />
public IRenderTargetBitmapImpl CreateLayer(Size size)
{
var normalizedDpi = new Vector(_dpi.X / SkiaPlatform.DefaultDpi.X, _dpi.Y / SkiaPlatform.DefaultDpi.Y);
var pixelSize = size * normalizedDpi;
return CreateRenderTarget((int) pixelSize.Width, (int) pixelSize.Height, _dpi);
return CreateRenderTarget(size);
}
/// <inheritdoc />
@ -387,26 +384,27 @@ namespace Avalonia.Skia
/// <param name="targetSize">Target size.</param>
/// <param name="tileBrush">Tile brush to use.</param>
/// <param name="tileBrushImage">Tile brush image.</param>
/// <param name="interpolationMode">The bitmap interpolation mode.</param>
private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage)
{
var calc = new TileBrushCalculator(tileBrush,
new Size(tileBrushImage.PixelSize.Width, tileBrushImage.PixelSize.Height), targetSize);
var intermediate = CreateRenderTarget(
(int)calc.IntermediateSize.Width,
(int)calc.IntermediateSize.Height, _dpi);
var calc = new TileBrushCalculator(tileBrush, tileBrushImage.PixelSize.ToSize(_dpi), targetSize);
var intermediate = CreateRenderTarget(calc.IntermediateSize);
paintWrapper.AddDisposable(intermediate);
using (var context = intermediate.CreateDrawingContext(null))
{
var rect = new Rect(0, 0, tileBrushImage.PixelSize.Width, tileBrushImage.PixelSize.Height);
var sourceRect = new Rect(tileBrushImage.PixelSize.ToSize(96));
var targetRect = new Rect(tileBrushImage.PixelSize.ToSize(_dpi));
context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip);
context.Transform = calc.IntermediateTransform;
context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect, tileBrush.BitmapInterpolationMode);
context.DrawImage(
RefCountable.CreateUnownedNotClonable(tileBrushImage),
1,
sourceRect,
targetRect,
tileBrush.BitmapInterpolationMode);
context.PopClip();
}
@ -433,7 +431,14 @@ namespace Avalonia.Skia
var image = intermediate.SnapshotImage();
paintWrapper.AddDisposable(image);
using (var shader = image.ToShader(tileX, tileY, tileTransform))
var paintTransform = default(SKMatrix);
SKMatrix.Concat(
ref paintTransform,
tileTransform,
SKMatrix.MakeScale((float)(96.0 / _dpi.X), (float)(96.0 / _dpi.Y)));
using (var shader = image.ToShader(tileX, tileY, paintTransform))
{
paintWrapper.Paint.Shader = shader;
}
@ -457,7 +462,7 @@ namespace Avalonia.Skia
if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1)
{
var intermediate = CreateRenderTarget((int)intermediateSize.Width, (int)intermediateSize.Height, _dpi);
var intermediate = CreateRenderTarget(intermediateSize);
using (var ctx = intermediate.CreateDrawingContext(visualBrushRenderer))
{
@ -609,18 +614,17 @@ namespace Avalonia.Skia
/// <summary>
/// Create new render target compatible with this drawing context.
/// </summary>
/// <param name="width">Width.</param>
/// <param name="height">Height.</param>
/// <param name="dpi">Drawing dpi.</param>
/// <param name="size">The size of the render target in DIPs.</param>
/// <param name="format">Pixel format.</param>
/// <returns></returns>
private SurfaceRenderTarget CreateRenderTarget(int width, int height, Vector dpi, PixelFormat? format = null)
private SurfaceRenderTarget CreateRenderTarget(Size size, PixelFormat? format = null)
{
var pixelSize = PixelSize.FromSize(size, _dpi);
var createInfo = new SurfaceRenderTarget.CreateInfo
{
Width = width,
Height = height,
Dpi = dpi,
Width = pixelSize.Width,
Height = pixelSize.Height,
Dpi = _dpi,
Format = format,
DisableTextLcdRendering = !_canTextUseLcdRendering,
GrContext = _grContext

8
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -434,10 +434,16 @@ namespace Avalonia.Direct2D1.Media
if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1)
{
// We need to ensure the size we're requesting is an integer pixel size, otherwise
// D2D alters the DPI of the render target, which messes stuff up. PixelSize.FromSize
// will do the rounding for us.
var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height);
var pixelSize = PixelSize.FromSize(intermediateSize, dpi);
using (var intermediate = new BitmapRenderTarget(
_deviceContext,
CompatibleRenderTargetOptions.None,
intermediateSize.ToSharpDX()))
pixelSize.ToSize(dpi).ToSharpDX()))
{
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(_visualBrushRenderer))
{

6
src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs

@ -20,7 +20,8 @@ namespace Avalonia.Direct2D1.Media
BitmapImpl bitmap,
Size targetSize)
{
var calc = new TileBrushCalculator(brush, bitmap.PixelSize.ToSize(96), targetSize);
var dpi = new Vector(target.DotsPerInch.Width, target.DotsPerInch.Height);
var calc = new TileBrushCalculator(brush, bitmap.PixelSize.ToSize(dpi), targetSize);
if (!calc.NeedsIntermediate)
{
@ -99,7 +100,8 @@ namespace Avalonia.Direct2D1.Media
using (var context = new RenderTarget(result).CreateDrawingContext(null))
{
var rect = new Rect(0, 0, bitmap.PixelSize.Width, bitmap.PixelSize.Height);
var dpi = new Vector(target.DotsPerInch.Width, target.DotsPerInch.Height);
var rect = new Rect(bitmap.PixelSize.ToSize(dpi));
context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip);

19
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs

@ -1,8 +1,10 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.IO;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Utilities;
using SharpDX;
using SharpDX.Direct2D1;
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
@ -49,5 +51,22 @@ namespace Avalonia.Direct2D1.Media.Imaging
{
return new OptionalDispose<D2DBitmap>(_renderTarget.Bitmap, false);
}
public override void Save(Stream stream)
{
using (var wic = new WicRenderTargetBitmapImpl(PixelSize, Dpi))
{
using (var dc = wic.CreateDrawingContext(null))
{
dc.DrawImage(
RefCountable.CreateUnownedNotClonable(this),
1,
new Rect(PixelSize.ToSize(Dpi.X)),
new Rect(PixelSize.ToSize(Dpi.X)));
}
wic.Save(stream);
}
}
}
}

13
src/Windows/Avalonia.Direct2D1/Utils/DebugUtils.cs

@ -0,0 +1,13 @@
using Avalonia.Direct2D1.Media.Imaging;
namespace Avalonia.Direct2D1.Utils
{
internal static class DebugUtils
{
public static void Save(SharpDX.Direct2D1.BitmapRenderTarget bitmap, string filename)
{
var rtb = new D2DRenderTargetBitmapImpl(bitmap);
rtb.Save(filename);
}
}
}

276
tests/Avalonia.RenderTests/Media/VisualBrushTests.cs

@ -449,5 +449,281 @@ namespace Avalonia.Direct2D1.RenderTests.Media
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task VisualBrush_Grip_96_Dpi()
{
var target = new Border
{
Width = 100,
Height = 10,
Background = new VisualBrush
{
SourceRect = new RelativeRect(0, 0, 4, 5, RelativeUnit.Absolute),
DestinationRect = new RelativeRect(0, 0, 4, 5, RelativeUnit.Absolute),
TileMode = TileMode.Tile,
Stretch = Stretch.UniformToFill,
Visual = new Canvas
{
Width = 4,
Height = 5,
Background = Brushes.WhiteSmoke,
Children =
{
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.LeftProperty] = 2,
},
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.TopProperty] = 2,
},
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.LeftProperty] = 2,
[Canvas.TopProperty] = 4,
}
}
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task VisualBrush_Grip_144_Dpi()
{
var target = new Border
{
Width = 100,
Height = 7.5,
Background = new VisualBrush
{
SourceRect = new RelativeRect(0, 0, 4, 5, RelativeUnit.Absolute),
DestinationRect = new RelativeRect(0, 0, 4, 5, RelativeUnit.Absolute),
TileMode = TileMode.Tile,
Stretch = Stretch.UniformToFill,
Visual = new Canvas
{
Width = 4,
Height = 5,
Background = Brushes.WhiteSmoke,
Children =
{
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.LeftProperty] = 2,
},
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.TopProperty] = 2,
},
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.LeftProperty] = 2,
[Canvas.TopProperty] = 4,
}
}
}
}
};
await RenderToFile(target, dpi: 144);
CompareImages();
}
[Fact]
public async Task VisualBrush_Grip_192_Dpi()
{
var target = new Border
{
Width = 100,
Height = 10,
Background = new VisualBrush
{
SourceRect = new RelativeRect(0, 0, 4, 5, RelativeUnit.Absolute),
DestinationRect = new RelativeRect(0, 0, 4, 5, RelativeUnit.Absolute),
TileMode = TileMode.Tile,
Stretch = Stretch.UniformToFill,
Visual = new Canvas
{
Width = 4,
Height = 5,
Background = Brushes.WhiteSmoke,
Children =
{
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.LeftProperty] = 2,
},
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.TopProperty] = 2,
},
new Rectangle
{
Width = 1,
Height = 1,
Fill = Brushes.Red,
[Canvas.LeftProperty] = 2,
[Canvas.TopProperty] = 4,
}
}
}
}
};
await RenderToFile(target, dpi: 192);
CompareImages();
}
[Fact]
public async Task VisualBrush_Checkerboard_96_Dpi()
{
var target = new Border
{
Width = 200,
Height = 200,
Background = new VisualBrush
{
DestinationRect = new RelativeRect(0, 0, 16, 16, RelativeUnit.Absolute),
TileMode = TileMode.Tile,
Visual = new Canvas
{
Width = 16,
Height= 16,
Background = Brushes.Red,
Children =
{
new Rectangle
{
Width = 8,
Height = 8,
Fill = Brushes.Green,
},
new Rectangle
{
Width = 8,
Height = 8,
Fill = Brushes.Green,
[Canvas.LeftProperty] = 8,
[Canvas.TopProperty] = 8,
},
}
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task VisualBrush_Checkerboard_144_Dpi()
{
var target = new Border
{
Width = 200,
Height = 200,
Background = new VisualBrush
{
DestinationRect = new RelativeRect(0, 0, 16, 16, RelativeUnit.Absolute),
TileMode = TileMode.Tile,
Visual = new Canvas
{
Width = 16,
Height = 16,
Background = Brushes.Red,
Children =
{
new Rectangle
{
Width = 8,
Height = 8,
Fill = Brushes.Green,
},
new Rectangle
{
Width = 8,
Height = 8,
Fill = Brushes.Green,
[Canvas.LeftProperty] = 8,
[Canvas.TopProperty] = 8,
},
}
}
}
};
await RenderToFile(target, dpi: 144);
CompareImages();
}
[Fact]
public async Task VisualBrush_Checkerboard_192_Dpi()
{
var target = new Border
{
Width = 200,
Height = 200,
Background = new VisualBrush
{
DestinationRect = new RelativeRect(0, 0, 16, 16, RelativeUnit.Absolute),
TileMode = TileMode.Tile,
Visual = new Canvas
{
Width = 16,
Height = 16,
Background = Brushes.Red,
Children =
{
new Rectangle
{
Width = 8,
Height = 8,
Fill = Brushes.Green,
},
new Rectangle
{
Width = 8,
Height = 8,
Fill = Brushes.Green,
[Canvas.LeftProperty] = 8,
[Canvas.TopProperty] = 8,
},
}
}
}
};
await RenderToFile(target, dpi: 192);
CompareImages();
}
}
}

8
tests/Avalonia.RenderTests/TestBase.cs

@ -63,7 +63,7 @@ namespace Avalonia.Direct2D1.RenderTests
get;
}
protected async Task RenderToFile(Control target, [CallerMemberName] string testName = "")
protected async Task RenderToFile(Control target, [CallerMemberName] string testName = "", double dpi = 96)
{
if (!Directory.Exists(OutputPath))
{
@ -75,9 +75,9 @@ namespace Avalonia.Direct2D1.RenderTests
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var pixelSize = new PixelSize((int)target.Width, (int)target.Height);
var size = new Size(target.Width, target.Height);
var dpi = new Vector(96, 96);
var dpiVector = new Vector(dpi, dpi);
using (RenderTargetBitmap bitmap = new RenderTargetBitmap(pixelSize, dpi))
using (RenderTargetBitmap bitmap = new RenderTargetBitmap(pixelSize, dpiVector))
{
target.Measure(size);
target.Arrange(new Rect(size));
@ -85,7 +85,7 @@ namespace Avalonia.Direct2D1.RenderTests
bitmap.Save(immediatePath);
}
using (var rtb = factory.CreateRenderTargetBitmap(pixelSize, dpi))
using (var rtb = factory.CreateRenderTargetBitmap(pixelSize, dpiVector))
using (var renderer = new DeferredRenderer(target, rtb))
{
target.Measure(size);

5
tests/Avalonia.UnitTests/MockAssetLoader.cs

@ -32,10 +32,9 @@ namespace Avalonia.UnitTests
return (Open(uri, baseUri), (Assembly)null);
}
public IEnumerable<(string absolutePath, Assembly assembly)> GetAssets(Uri uri)
public IEnumerable<Uri> GetAssets(Uri uri, Uri baseUri)
{
return _assets.Keys.Where(x => x.AbsolutePath.Contains(uri.AbsolutePath))
.Select(x => (x.AbsolutePath, Assembly.GetEntryAssembly()));
return _assets.Keys.Where(x => x.AbsolutePath.Contains(uri.AbsolutePath));
}
public void SetDefaultAssembly(Assembly asm)

BIN
tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Checkerboard_144_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

BIN
tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Checkerboard_192_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

BIN
tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Checkerboard_96_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

BIN
tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Grip_144_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

BIN
tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Grip_192_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

BIN
tests/TestFiles/Direct2D1/Media/VisualBrush/VisualBrush_Grip_96_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

BIN
tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Checkerboard_144_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

BIN
tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Checkerboard_192_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

BIN
tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Checkerboard_96_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

BIN
tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Grip_144_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

BIN
tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Grip_192_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

BIN
tests/TestFiles/Skia/Media/VisualBrush/VisualBrush_Grip_96_Dpi.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Loading…
Cancel
Save