Browse Source

Merge branch 'master' into refactor/new-value-store

refactor/style-priorities
Steven Kirk 4 years ago
committed by GitHub
parent
commit
7211f031ac
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Avalonia.sln
  2. 6
      azure-pipelines.yml
  3. 6
      samples/BindingDemo/App.xaml
  4. 2
      samples/BindingDemo/BindingDemo.csproj
  5. 1
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  6. 20
      samples/ControlCatalog/App.xaml.cs
  7. 2
      samples/ControlCatalog/ControlCatalog.csproj
  8. 4
      samples/ControlCatalog/MainView.xaml
  9. 20
      samples/ControlCatalog/MainView.xaml.cs
  10. 10
      samples/ControlCatalog/Models/CatalogTheme.cs
  11. 9
      samples/ControlCatalog/Pages/DataGridPage.xaml
  12. 26
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  13. 44
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  14. 2
      samples/ControlCatalog/Pages/TextBlockPage.xaml
  15. 3
      samples/PlatformSanityChecks/App.xaml
  16. 2
      samples/PlatformSanityChecks/PlatformSanityChecks.csproj
  17. 5
      samples/Previewer/App.xaml
  18. 2
      samples/Previewer/Previewer.csproj
  19. 8
      samples/RenderDemo/App.xaml
  20. 16
      samples/VirtualizationDemo/App.xaml
  21. 2
      samples/VirtualizationDemo/VirtualizationDemo.csproj
  22. 5
      samples/interop/Direct3DInteropSample/App.paml
  23. 2
      samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
  24. 33
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
  25. 111
      src/Avalonia.Base/Media/GlyphRun.cs
  26. 2
      src/Avalonia.Base/Media/TextDecoration.cs
  27. 24
      src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs
  28. 17
      src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs
  29. 26
      src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
  30. 58
      src/Avalonia.Base/Media/TextFormatting/TextLayout.cs
  31. 2
      src/Avalonia.Base/Media/TextFormatting/TextLine.cs
  32. 737
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  33. 2
      src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs
  34. 4
      src/Avalonia.Base/Platform/IGeometryImpl.cs
  35. 8
      src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs
  36. 16
      src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs
  37. 2
      src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs
  38. 4
      src/Avalonia.Base/Platform/Storage/IStorageFile.cs
  39. 11
      src/Avalonia.Base/Platform/Storage/IStorageFolder.cs
  40. 2
      src/Avalonia.Base/Platform/Storage/IStorageItem.cs
  41. 5
      src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
  42. 11
      src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
  43. 4
      src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs
  44. 6
      src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs
  45. 4
      src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs
  46. 4
      src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs
  47. 4
      src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs
  48. 4
      src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
  49. 4
      src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs
  50. 8
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs
  51. 4
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
  52. 4
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs
  53. 4
      src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs
  54. 2
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  55. 4
      src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
  56. 4
      src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
  57. 4
      src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
  58. 4
      src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
  59. 4
      src/Avalonia.Base/Rendering/Composition/Compositor.cs
  60. 4
      src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs
  61. 4
      src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs
  62. 5
      src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
  63. 4
      src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs
  64. 4
      src/Avalonia.Base/Rendering/Composition/Enums.cs
  65. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs
  66. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs
  67. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
  68. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs
  69. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParseException.cs
  70. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParser.cs
  71. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionTrackedValues.cs
  72. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs
  73. 4
      src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs
  74. 4
      src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs
  75. 7
      src/Avalonia.Base/Rendering/Composition/License.md
  76. 4
      src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs
  77. 4
      src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs
  78. 4
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
  79. 4
      src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs
  80. 4
      src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs
  81. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs
  82. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
  83. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionSurface.cs
  84. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  85. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs
  86. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
  87. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
  88. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs
  89. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs
  90. 4
      src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs
  91. 2
      src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs
  92. 4
      src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamArrayPool.cs
  93. 4
      src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamDebugMarker.cs
  94. 4
      src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs
  95. 4
      src/Avalonia.Base/Rendering/Composition/Visual.cs
  96. 4
      src/Avalonia.Base/Rendering/Composition/VisualCollection.cs
  97. 3
      src/Avalonia.Base/Rendering/Composition/readme.md
  98. 2
      src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs
  99. 4
      src/Avalonia.Base/Rendering/SceneGraph/GeometryNode.cs
  100. 8
      src/Avalonia.Base/Rendering/SceneGraph/GlyphRunNode.cs

2
Avalonia.sln

@ -13,7 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\W
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Default", "src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Simple", "src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Diagnostics", "src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Diagnostics", "src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}"
EndProject EndProject

6
azure-pipelines.yml

@ -59,7 +59,7 @@ jobs:
variables: variables:
SolutionDir: '$(Build.SourcesDirectory)' SolutionDir: '$(Build.SourcesDirectory)'
pool: pool:
vmImage: 'macOS-10.15' vmImage: 'macos-12'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.418' displayName: 'Use .NET Core SDK 3.1.418'
@ -91,10 +91,10 @@ jobs:
inputs: inputs:
actions: 'build' actions: 'build'
scheme: '' scheme: ''
sdk: 'macosx11.1' sdk: 'macosx12.3'
configuration: 'Release' configuration: 'Release'
xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
xcodeVersion: '12' # Options: 8, 9, default, specifyPath xcodeVersion: '13' # Options: 8, 9, default, specifyPath
args: '-derivedDataPath ./' args: '-derivedDataPath ./'
- task: CmdLine@2 - task: CmdLine@2

6
samples/BindingDemo/App.xaml

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BindingDemo.App"> x:Class="BindingDemo.App">
<Application.Styles> <Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/> <FluentTheme />
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Simple/Accents/BaseLight.xaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/BindingDemo/BindingDemo.csproj

@ -5,7 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup> </ItemGroup>

1
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -9,7 +9,6 @@
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<AndroidPackageFormat>apk</AndroidPackageFormat> <AndroidPackageFormat>apk</AndroidPackageFormat>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver> <MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<RuntimeIdentifiers>android-arm64;android-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="..\..\build\Assets\Icon.png"> <AndroidResource Include="..\..\build\Assets\Icon.png">

20
samples/ControlCatalog/App.xaml.cs

@ -5,7 +5,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling; using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Themes.Default; using Avalonia.Themes.Simple;
using Avalonia.Themes.Fluent; using Avalonia.Themes.Fluent;
using ControlCatalog.ViewModels; using ControlCatalog.ViewModels;
@ -23,9 +23,9 @@ namespace ControlCatalog
Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml") Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml")
}; };
public static readonly StyleInclude ColorPickerDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) public static readonly StyleInclude ColorPickerSimple = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{ {
Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml") Source = new Uri("avares://Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml")
}; };
public static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) public static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
@ -33,16 +33,16 @@ namespace ControlCatalog
Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml") Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml")
}; };
public static readonly StyleInclude DataGridDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles")) public static readonly StyleInclude DataGridSimple = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{ {
Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Default.xaml") Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Simple.xaml")
}; };
public static FluentTheme Fluent = new FluentTheme(new Uri("avares://ControlCatalog/Styles")); public static FluentTheme Fluent = new FluentTheme(new Uri("avares://ControlCatalog/Styles"));
public static SimpleTheme Default = new SimpleTheme(new Uri("avares://ControlCatalog/Styles")); public static SimpleTheme Simple = new SimpleTheme(new Uri("avares://ControlCatalog/Styles"));
public static Styles DefaultLight = new Styles public static Styles SimpleLight = new Styles
{ {
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{ {
@ -56,10 +56,10 @@ namespace ControlCatalog
{ {
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseLight.xaml") Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseLight.xaml")
}, },
Default Simple
}; };
public static Styles DefaultDark = new Styles public static Styles SimpleDark = new Styles
{ {
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{ {
@ -73,7 +73,7 @@ namespace ControlCatalog
{ {
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseDark.xaml") Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseDark.xaml")
}, },
Default Simple
}; };
public override void Initialize() public override void Initialize()

2
samples/ControlCatalog/ControlCatalog.csproj

@ -29,7 +29,7 @@
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.ColorPicker\Avalonia.Controls.ColorPicker.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
<ProjectReference Include="..\SampleControls\ControlSamples.csproj" /> <ProjectReference Include="..\SampleControls\ControlSamples.csproj" />

4
samples/ControlCatalog/MainView.xaml

@ -187,8 +187,8 @@
<ComboBox.Items> <ComboBox.Items>
<models:CatalogTheme>FluentLight</models:CatalogTheme> <models:CatalogTheme>FluentLight</models:CatalogTheme>
<models:CatalogTheme>FluentDark</models:CatalogTheme> <models:CatalogTheme>FluentDark</models:CatalogTheme>
<models:CatalogTheme>DefaultLight</models:CatalogTheme> <models:CatalogTheme>SimpleLight</models:CatalogTheme>
<models:CatalogTheme>DefaultDark</models:CatalogTheme> <models:CatalogTheme>SimpleDark</models:CatalogTheme>
</ComboBox.Items> </ComboBox.Items>
</ComboBox> </ComboBox>
<ComboBox x:Name="TransparencyLevels" <ComboBox x:Name="TransparencyLevels"

20
samples/ControlCatalog/MainView.xaml.cs

@ -58,19 +58,19 @@ namespace ControlCatalog
Application.Current.Styles[1] = App.ColorPickerFluent; Application.Current.Styles[1] = App.ColorPickerFluent;
Application.Current.Styles[2] = App.DataGridFluent; Application.Current.Styles[2] = App.DataGridFluent;
} }
else if (theme == CatalogTheme.DefaultLight) else if (theme == CatalogTheme.SimpleLight)
{ {
App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Light; App.Simple.Mode = Avalonia.Themes.Simple.SimpleThemeMode.Light;
Application.Current.Styles[0] = App.DefaultLight; Application.Current.Styles[0] = App.SimpleLight;
Application.Current.Styles[1] = App.ColorPickerDefault; Application.Current.Styles[1] = App.ColorPickerSimple;
Application.Current.Styles[2] = App.DataGridDefault; Application.Current.Styles[2] = App.DataGridSimple;
} }
else if (theme == CatalogTheme.DefaultDark) else if (theme == CatalogTheme.SimpleDark)
{ {
App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Dark; App.Simple.Mode = Avalonia.Themes.Simple.SimpleThemeMode.Dark;
Application.Current.Styles[0] = App.DefaultDark; Application.Current.Styles[0] = App.SimpleDark;
Application.Current.Styles[1] = App.ColorPickerDefault; Application.Current.Styles[1] = App.ColorPickerSimple;
Application.Current.Styles[2] = App.DataGridDefault; Application.Current.Styles[2] = App.DataGridSimple;
} }
} }
}; };

10
samples/ControlCatalog/Models/CatalogTheme.cs

@ -1,14 +1,10 @@
using System; namespace ControlCatalog.Models
using System.Collections.Generic;
using System.Text;
namespace ControlCatalog.Models
{ {
public enum CatalogTheme public enum CatalogTheme
{ {
FluentLight, FluentLight,
FluentDark, FluentDark,
DefaultLight, SimpleLight,
DefaultDark SimpleDark
} }
} }

9
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -10,11 +10,11 @@
<TextBlock Text="{Binding}"/> <TextBlock Text="{Binding}"/>
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
<ControlTheme x:Key="GdpCell" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</ControlTheme>
</UserControl.Resources> </UserControl.Resources>
<UserControl.Styles> <UserControl.Styles>
<Style Selector="DataGridCell.gdp">
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</Style>
<Style Selector="DataGridColumnHeader:nth-last-child(1)"> <Style Selector="DataGridColumnHeader:nth-last-child(1)">
<Setter Property="FontWeight" Value="Bold" /> <Setter Property="FontWeight" Value="Bold" />
</Style> </Style>
@ -54,7 +54,8 @@
<DataGridTextColumn Header="Region" Binding="{CompiledBinding Region}" Width="4*" x:DataType="local:Country" /> <DataGridTextColumn Header="Region" Binding="{CompiledBinding Region}" Width="4*" x:DataType="local:Country" />
<DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" /> <DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" />
<DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" /> <DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" />
<DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" CellStyleClasses="gdp" <DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*"
CellTheme="{StaticResource GdpCell}"
MinWidth="200" MinWidth="200"
IsVisible="{Binding #ShowGDP.IsChecked}"/> IsVisible="{Binding #ShowGDP.IsChecked}"/>
</DataGrid.Columns> </DataGrid.Columns>

26
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -195,10 +195,10 @@ namespace ControlCatalog.Pages
{ {
// Sync disposal of StreamWriter is not supported on WASM // Sync disposal of StreamWriter is not supported on WASM
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
await using var stream = await file.OpenWrite(); await using var stream = await file.OpenWriteAsync();
await using var reader = new System.IO.StreamWriter(stream); await using var reader = new System.IO.StreamWriter(stream);
#else #else
using var stream = await file.OpenWrite(); using var stream = await file.OpenWriteAsync();
using var reader = new System.IO.StreamWriter(stream); using var reader = new System.IO.StreamWriter(stream);
#endif #endif
await reader.WriteLineAsync(openedFileContent.Text); await reader.WriteLineAsync(openedFileContent.Text);
@ -243,8 +243,8 @@ namespace ControlCatalog.Pages
async Task SetPickerResult(IReadOnlyCollection<IStorageItem>? items) async Task SetPickerResult(IReadOnlyCollection<IStorageItem>? items)
{ {
items ??= Array.Empty<IStorageItem>(); items ??= Array.Empty<IStorageItem>();
var mappedResults = items.Select(FullPathOrName).ToList(); bookmarkContainer.Text = items.FirstOrDefault(f => f.CanBookmark) is { } f ? await f.SaveBookmarkAsync() : "Can't bookmark";
bookmarkContainer.Text = items.FirstOrDefault(f => f.CanBookmark) is { } f ? await f.SaveBookmark() : "Can't bookmark"; var mappedResults = new List<string>();
if (items.FirstOrDefault() is IStorageItem item) if (items.FirstOrDefault() is IStorageItem item)
{ {
@ -267,9 +267,9 @@ Content:
if (file.CanOpenRead) if (file.CanOpenRead)
{ {
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
await using var stream = await file.OpenRead(); await using var stream = await file.OpenReadAsync();
#else #else
using var stream = await file.OpenRead(); using var stream = await file.OpenReadAsync();
#endif #endif
using var reader = new System.IO.StreamReader(stream); using var reader = new System.IO.StreamReader(stream);
@ -293,7 +293,19 @@ Content:
lastSelectedDirectory = await item.GetParentAsync(); lastSelectedDirectory = await item.GetParentAsync();
if (lastSelectedDirectory is not null) if (lastSelectedDirectory is not null)
{ {
mappedResults.Insert(0, "Parent: " + FullPathOrName(lastSelectedDirectory)); mappedResults.Add(FullPathOrName(lastSelectedDirectory));
}
foreach (var selectedItem in items)
{
mappedResults.Add("+> " + FullPathOrName(selectedItem));
if (selectedItem is IStorageFolder folder)
{
foreach (var innerItems in await folder.GetItemsAsync())
{
mappedResults.Add("++> " + FullPathOrName(innerItems));
}
}
} }
} }

44
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@ -90,7 +90,6 @@ namespace ControlCatalog.Pages
private int _vertexBufferObject; private int _vertexBufferObject;
private int _indexBufferObject; private int _indexBufferObject;
private int _vertexArrayObject; private int _vertexArrayObject;
private GlExtrasInterface _glExt;
private string GetShader(bool fragment, string shader) private string GetShader(bool fragment, string shader)
{ {
@ -258,7 +257,6 @@ namespace ControlCatalog.Pages
protected unsafe override void OnOpenGlInit(GlInterface GL, int fb) protected unsafe override void OnOpenGlInit(GlInterface GL, int fb)
{ {
CheckError(GL); CheckError(GL);
_glExt = new GlExtrasInterface(GL);
Info = $"Renderer: {GL.GetString(GL_RENDERER)} Version: {GL.GetString(GL_VERSION)}"; Info = $"Renderer: {GL.GetString(GL_RENDERER)} Version: {GL.GetString(GL_VERSION)}";
@ -298,8 +296,8 @@ namespace ControlCatalog.Pages
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata), GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata),
GL_STATIC_DRAW); GL_STATIC_DRAW);
CheckError(GL); CheckError(GL);
_vertexArrayObject = _glExt.GenVertexArray(); _vertexArrayObject = GL.GenVertexArray();
_glExt.BindVertexArray(_vertexArrayObject); GL.BindVertexArray(_vertexArrayObject);
CheckError(GL); CheckError(GL);
GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT, GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT,
0, vertexSize, IntPtr.Zero); 0, vertexSize, IntPtr.Zero);
@ -316,12 +314,13 @@ namespace ControlCatalog.Pages
// Unbind everything // Unbind everything
GL.BindBuffer(GL_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ARRAY_BUFFER, 0);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
_glExt.BindVertexArray(0); GL.BindVertexArray(0);
GL.UseProgram(0); GL.UseProgram(0);
// Delete all resources. // Delete all resources.
GL.DeleteBuffers(2, new[] { _vertexBufferObject, _indexBufferObject }); GL.DeleteBuffer(_vertexBufferObject);
_glExt.DeleteVertexArrays(1, new[] { _vertexArrayObject }); GL.DeleteBuffer(_indexBufferObject);
GL.DeleteVertexArray(_vertexArrayObject);
GL.DeleteProgram(_shaderProgram); GL.DeleteProgram(_shaderProgram);
GL.DeleteShader(_fragmentShader); GL.DeleteShader(_fragmentShader);
GL.DeleteShader(_vertexShader); GL.DeleteShader(_vertexShader);
@ -338,7 +337,7 @@ namespace ControlCatalog.Pages
GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject); GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject);
_glExt.BindVertexArray(_vertexArrayObject); GL.BindVertexArray(_vertexArrayObject);
GL.UseProgram(_shaderProgram); GL.UseProgram(_shaderProgram);
CheckError(GL); CheckError(GL);
var projection = var projection =
@ -369,34 +368,5 @@ namespace ControlCatalog.Pages
if (_disco > 0.01) if (_disco > 0.01)
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
} }
class GlExtrasInterface : GlInterfaceBase<GlInterface.GlContextInfo>
{
public GlExtrasInterface(GlInterface gl) : base(gl.GetProcAddress, gl.ContextInfo)
{
}
public delegate void GlDeleteVertexArrays(int count, int[] buffers);
[GlMinVersionEntryPoint("glDeleteVertexArrays", 3,0)]
[GlExtensionEntryPoint("glDeleteVertexArraysOES", "GL_OES_vertex_array_object")]
public GlDeleteVertexArrays DeleteVertexArrays { get; }
public delegate void GlBindVertexArray(int array);
[GlMinVersionEntryPoint("glBindVertexArray", 3,0)]
[GlExtensionEntryPoint("glBindVertexArrayOES", "GL_OES_vertex_array_object")]
public GlBindVertexArray BindVertexArray { get; }
public delegate void GlGenVertexArrays(int n, int[] rv);
[GlMinVersionEntryPoint("glGenVertexArrays",3,0)]
[GlExtensionEntryPoint("glGenVertexArraysOES", "GL_OES_vertex_array_object")]
public GlGenVertexArrays GenVertexArrays { get; }
public int GenVertexArray()
{
var rv = new int[1];
GenVertexArrays(1, rv);
return rv[0];
}
}
} }
} }

2
samples/ControlCatalog/Pages/TextBlockPage.xaml

@ -118,7 +118,7 @@
</StackPanel> </StackPanel>
</Border> </Border>
<Border> <Border>
<RichTextBlock Margin="10" TextWrapping="Wrap"> <RichTextBlock SelectionBrush="LightBlue" IsTextSelectionEnabled="True" Margin="10" TextWrapping="Wrap">
This <Span FontWeight="Bold">is</Span> a This <Span FontWeight="Bold">is</Span> a
<Span Background="Silver" Foreground="Maroon">TextBlock</Span> <Span Background="Silver" Foreground="Maroon">TextBlock</Span>
with <Span TextDecorations="Underline">several</Span> with <Span TextDecorations="Underline">several</Span>

3
samples/PlatformSanityChecks/App.xaml

@ -1,6 +1,5 @@
<Application xmlns="https://github.com/avaloniaui"> <Application xmlns="https://github.com/avaloniaui">
<Application.Styles> <Application.Styles>
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/> <SimpleTheme Mode="Light" />
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/PlatformSanityChecks/PlatformSanityChecks.csproj

@ -7,7 +7,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" /> <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
</ItemGroup> </ItemGroup>

5
samples/Previewer/App.xaml

@ -1,6 +1,5 @@
<Application xmlns="https://github.com/avaloniaui"> <Application xmlns="https://github.com/avaloniaui">
<Application.Styles> <Application.Styles>
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/> <SimpleTheme Mode="Light" />
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/Previewer/Previewer.csproj

@ -10,7 +10,7 @@
<EmbeddedResource Include="**\*.xaml" /> <EmbeddedResource Include="**\*.xaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\SampleApp.props" /> <Import Project="..\..\build\SampleApp.props" />

8
samples/RenderDemo/App.xaml

@ -3,6 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Styles> <Application.Styles>
<FluentTheme /> <FluentTheme />
<StyleInclude Source="avares://ControlSamples/HamburgerMenu/HamburgerMenu.xaml" />
</Application.Styles> </Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://ControlSamples/HamburgerMenu/HamburgerMenu.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application> </Application>

16
samples/VirtualizationDemo/App.xaml

@ -1,9 +1,7 @@
<Application <Application xmlns="https://github.com/avaloniaui"
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="VirtualizationDemo.App">
x:Class="VirtualizationDemo.App"> <Application.Styles>
<Application.Styles> <SimpleTheme />
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/> </Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/> </Application>
</Application.Styles>
</Application>

2
samples/VirtualizationDemo/VirtualizationDemo.csproj

@ -5,7 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup> </ItemGroup>

5
samples/interop/Direct3DInteropSample/App.paml

@ -1,6 +1,5 @@
<Application xmlns="https://github.com/avaloniaui"> <Application xmlns="https://github.com/avaloniaui">
<Application.Styles> <Application.Styles>
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/> <SimpleTheme Mode="Light" />
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj

@ -22,7 +22,7 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" /> <ProjectReference Include="..\..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" /> <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" /> <ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
<ProjectReference Include="..\..\MiniMvvm\MiniMvvm.csproj" /> <ProjectReference Include="..\..\MiniMvvm\MiniMvvm.csproj" />

33
src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

@ -1,6 +1,7 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -35,13 +36,13 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem
public bool CanBookmark => true; public bool CanBookmark => true;
public Task<string?> SaveBookmark() public Task<string?> SaveBookmarkAsync()
{ {
Context.ContentResolver?.TakePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission); Context.ContentResolver?.TakePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission);
return Task.FromResult(Uri.ToString()); return Task.FromResult(Uri.ToString());
} }
public Task ReleaseBookmark() public Task ReleaseBookmarkAsync()
{ {
Context.ContentResolver?.ReleasePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission); Context.ContentResolver?.ReleasePersistableUriPermission(Uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantReadUriPermission);
return Task.CompletedTask; return Task.CompletedTask;
@ -106,6 +107,30 @@ internal sealed class AndroidStorageFolder : AndroidStorageItem, IStorageBookmar
{ {
return Task.FromResult(new StorageItemProperties()); return Task.FromResult(new StorageItemProperties());
} }
public async Task<IReadOnlyList<IStorageItem>> GetItemsAsync()
{
using var javaFile = new JavaFile(Uri.Path!);
// Java file represents files AND directories. Don't be confused.
var files = await javaFile.ListFilesAsync().ConfigureAwait(false);
if (files is null)
{
return Array.Empty<IStorageItem>();
}
return files
.Select(f => (file: f, uri: AndroidUri.FromFile(f)))
.Where(t => t.uri is not null)
.Select(t => t.file switch
{
{ IsFile: true } => (IStorageItem)new AndroidStorageFile(Context, t.uri!),
{ IsDirectory: true } => new AndroidStorageFolder(Context, t.uri!),
_ => null
})
.Where(i => i is not null)
.ToArray()!;
}
} }
internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkFile internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkFile
@ -118,10 +143,10 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
public bool CanOpenWrite => true; public bool CanOpenWrite => true;
public Task<Stream> OpenRead() => Task.FromResult(OpenContentStream(Context, Uri, false) public Task<Stream> OpenReadAsync() => Task.FromResult(OpenContentStream(Context, Uri, false)
?? throw new InvalidOperationException("Failed to open content stream")); ?? throw new InvalidOperationException("Failed to open content stream"));
public Task<Stream> OpenWrite() => Task.FromResult(OpenContentStream(Context, Uri, true) public Task<Stream> OpenWriteAsync() => Task.FromResult(OpenContentStream(Context, Uri, true)
?? throw new InvalidOperationException("Failed to open content stream")); ?? throw new InvalidOperationException("Failed to open content stream"));
private Stream? OpenContentStream(Context context, AndroidUri uri, bool isOutput) private Stream? OpenContentStream(Context context, AndroidUri uri, bool isOutput)

111
src/Avalonia.Base/Media/GlyphRun.cs

@ -265,7 +265,7 @@ namespace Avalonia.Media
//RightToLeft //RightToLeft
var glyphIndex = FindGlyphIndex(characterIndex); var glyphIndex = FindGlyphIndex(characterIndex);
if (GlyphClusters != null) if (GlyphClusters != null && GlyphClusters.Count > 0)
{ {
if (characterIndex > GlyphClusters[0]) if (characterIndex > GlyphClusters[0])
{ {
@ -445,7 +445,7 @@ namespace Avalonia.Media
/// </returns> /// </returns>
public int FindGlyphIndex(int characterIndex) public int FindGlyphIndex(int characterIndex)
{ {
if (GlyphClusters == null) if (GlyphClusters == null || GlyphClusters.Count == 0)
{ {
return characterIndex; return characterIndex;
} }
@ -614,17 +614,29 @@ namespace Avalonia.Media
private GlyphRunMetrics CreateGlyphRunMetrics() private GlyphRunMetrics CreateGlyphRunMetrics()
{ {
var firstCluster = 0;
var lastCluster = Characters.Length - 1;
if (!IsLeftToRight)
{
var cluster = firstCluster;
firstCluster = lastCluster;
lastCluster = cluster;
}
if (GlyphClusters != null && GlyphClusters.Count > 0) if (GlyphClusters != null && GlyphClusters.Count > 0)
{ {
var firstCluster = GlyphClusters[0]; firstCluster = GlyphClusters[0];
lastCluster = GlyphClusters[GlyphClusters.Count - 1];
_offsetToFirstCharacter = Math.Max(0, Characters.Start - firstCluster); _offsetToFirstCharacter = Math.Max(0, Characters.Start - firstCluster);
} }
var isReversed = firstCluster > lastCluster;
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale; var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
var widthIncludingTrailingWhitespace = 0d; var widthIncludingTrailingWhitespace = 0d;
var trailingWhitespaceLength = GetTrailingWhitespaceLength(out var newLineLength, out var glyphCount); var trailingWhitespaceLength = GetTrailingWhitespaceLength(isReversed, out var newLineLength, out var glyphCount);
for (var index = 0; index < GlyphIndices.Count; index++) for (var index = 0; index < GlyphIndices.Count; index++)
{ {
@ -635,16 +647,16 @@ namespace Avalonia.Media
var width = widthIncludingTrailingWhitespace; var width = widthIncludingTrailingWhitespace;
if (IsLeftToRight) if (isReversed)
{ {
for (var index = GlyphIndices.Count - glyphCount; index < GlyphIndices.Count; index++) for (var index = 0; index < glyphCount; index++)
{ {
width -= GetGlyphAdvance(index, out _); width -= GetGlyphAdvance(index, out _);
} }
} }
else else
{ {
for (var index = 0; index < glyphCount; index++) for (var index = GlyphIndices.Count - glyphCount; index < GlyphIndices.Count; index++)
{ {
width -= GetGlyphAdvance(index, out _); width -= GetGlyphAdvance(index, out _);
} }
@ -654,16 +666,15 @@ namespace Avalonia.Media
height); height);
} }
private int GetTrailingWhitespaceLength(out int newLineLength, out int glyphCount) private int GetTrailingWhitespaceLength(bool isReversed, out int newLineLength, out int glyphCount)
{ {
glyphCount = 0; if (isReversed)
newLineLength = 0;
if (Characters.IsEmpty)
{ {
return 0; return GetTralingWhitespaceLengthRightToLeft(out newLineLength, out glyphCount);
} }
glyphCount = 0;
newLineLength = 0;
var trailingWhitespaceLength = 0; var trailingWhitespaceLength = 0;
if (GlyphClusters == null) if (GlyphClusters == null)
@ -732,6 +743,78 @@ namespace Avalonia.Media
return trailingWhitespaceLength; return trailingWhitespaceLength;
} }
private int GetTralingWhitespaceLengthRightToLeft(out int newLineLength, out int glyphCount)
{
glyphCount = 0;
newLineLength = 0;
var trailingWhitespaceLength = 0;
if (GlyphClusters == null)
{
for (var i = 0; i < Characters.Length;)
{
var codepoint = Codepoint.ReadAt(_characters, i, out var count);
if (!codepoint.IsWhiteSpace)
{
break;
}
if (codepoint.IsBreakChar)
{
newLineLength++;
}
trailingWhitespaceLength++;
i += count;
glyphCount++;
}
}
else
{
for (var i = 0; i < GlyphClusters.Count; i++)
{
var currentCluster = GlyphClusters[i];
var characterIndex = Math.Max(0, currentCluster - _characters.BufferOffset);
var codepoint = Codepoint.ReadAt(_characters, characterIndex, out _);
if (!codepoint.IsWhiteSpace)
{
break;
}
var clusterLength = 1;
while (i - 1 >= 0)
{
var nextCluster = GlyphClusters[i - 1];
if (currentCluster == nextCluster)
{
clusterLength++;
i--;
continue;
}
break;
}
if (codepoint.IsBreakChar)
{
newLineLength += clusterLength;
}
trailingWhitespaceLength += clusterLength;
glyphCount++;
}
}
return trailingWhitespaceLength;
}
private void Set<T>(ref T field, T value) private void Set<T>(ref T field, T value)
{ {
_glyphRunImpl?.Dispose(); _glyphRunImpl?.Dispose();

2
src/Avalonia.Base/Media/TextDecoration.cs

@ -209,7 +209,7 @@ namespace Avalonia.Media
var pen = new Pen(Stroke ?? defaultBrush, thickness, var pen = new Pen(Stroke ?? defaultBrush, thickness,
new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap); new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap);
drawingContext.DrawLine(pen, origin, origin + new Point(glyphRun.Size.Width, 0)); drawingContext.DrawLine(pen, origin, origin + new Point(glyphRun.Metrics.Width, 0));
} }
} }
} }

24
src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Utilities; using Avalonia.Utilities;
namespace Avalonia.Media.TextFormatting namespace Avalonia.Media.TextFormatting
@ -116,7 +117,30 @@ namespace Avalonia.Media.TextFormatting
length = text.Length; length = text.Length;
} }
length = CoerceLength(text, length);
return new ValueSpan<TextRunProperties>(firstTextSourceIndex, length, currentProperties); return new ValueSpan<TextRunProperties>(firstTextSourceIndex, length, currentProperties);
} }
private static int CoerceLength(ReadOnlySlice<char> text, int length)
{
var finalLength = 0;
var graphemeEnumerator = new GraphemeEnumerator(text);
while (graphemeEnumerator.MoveNext())
{
var grapheme = graphemeEnumerator.Current;
finalLength += grapheme.Text.Length;
if (finalLength >= length)
{
return finalLength;
}
}
return length;
}
} }
} }

17
src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs

@ -15,6 +15,13 @@ namespace Avalonia.Media.TextFormatting
public override void Justify(TextLine textLine) public override void Justify(TextLine textLine)
{ {
var lineImpl = textLine as TextLineImpl;
if(lineImpl is null)
{
return;
}
var paragraphWidth = Width; var paragraphWidth = Width;
if (double.IsInfinity(paragraphWidth)) if (double.IsInfinity(paragraphWidth))
@ -22,12 +29,12 @@ namespace Avalonia.Media.TextFormatting
return; return;
} }
if (textLine.NewLineLength > 0) if (lineImpl.NewLineLength > 0)
{ {
return; return;
} }
var textLineBreak = textLine.TextLineBreak; var textLineBreak = lineImpl.TextLineBreak;
if (textLineBreak is not null && textLineBreak.TextEndOfLine is not null) if (textLineBreak is not null && textLineBreak.TextEndOfLine is not null)
{ {
@ -39,7 +46,7 @@ namespace Avalonia.Media.TextFormatting
var breakOportunities = new Queue<int>(); var breakOportunities = new Queue<int>();
foreach (var textRun in textLine.TextRuns) foreach (var textRun in lineImpl.TextRuns)
{ {
var text = textRun.Text; var text = textRun.Text;
@ -68,10 +75,10 @@ namespace Avalonia.Media.TextFormatting
return; return;
} }
var remainingSpace = Math.Max(0, paragraphWidth - textLine.WidthIncludingTrailingWhitespace); var remainingSpace = Math.Max(0, paragraphWidth - lineImpl.WidthIncludingTrailingWhitespace);
var spacing = remainingSpace / breakOportunities.Count; var spacing = remainingSpace / breakOportunities.Count;
foreach (var textRun in textLine.TextRuns) foreach (var textRun in lineImpl.TextRuns)
{ {
var text = textRun.Text; var text = textRun.Text;

26
src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs

@ -38,7 +38,7 @@ namespace Avalonia.Media.TextFormatting
/// Gets a list of <see cref="ShapeableTextCharacters"/>. /// Gets a list of <see cref="ShapeableTextCharacters"/>.
/// </summary> /// </summary>
/// <returns>The shapeable text characters.</returns> /// <returns>The shapeable text characters.</returns>
internal IReadOnlyList<ShapeableTextCharacters> GetShapeableCharacters(ReadOnlySlice<char> runText, sbyte biDiLevel, internal IReadOnlyList<ShapeableTextCharacters> GetShapeableCharacters(ReadOnlySlice<char> runText, sbyte biDiLevel,
ref TextRunProperties? previousProperties) ref TextRunProperties? previousProperties)
{ {
var shapeableCharacters = new List<ShapeableTextCharacters>(2); var shapeableCharacters = new List<ShapeableTextCharacters>(2);
@ -65,7 +65,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="biDiLevel">The bidi level of the run.</param> /// <param name="biDiLevel">The bidi level of the run.</param>
/// <param name="previousProperties"></param> /// <param name="previousProperties"></param>
/// <returns>A list of shapeable text runs.</returns> /// <returns>A list of shapeable text runs.</returns>
private static ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice<char> text, private static ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice<char> text,
TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties? previousProperties) TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties? previousProperties)
{ {
var defaultTypeface = defaultProperties.Typeface; var defaultTypeface = defaultProperties.Typeface;
@ -76,7 +76,7 @@ namespace Avalonia.Media.TextFormatting
{ {
if (script == Script.Common && previousTypeface is not null) if (script == Script.Common && previousTypeface is not null)
{ {
if(TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out var fallbackCount, out _)) if (TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out var fallbackCount, out _))
{ {
return new ShapeableTextCharacters(text.Take(fallbackCount), return new ShapeableTextCharacters(text.Take(fallbackCount),
defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel); defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel);
@ -86,10 +86,10 @@ namespace Avalonia.Media.TextFormatting
return new ShapeableTextCharacters(text.Take(count), defaultProperties.WithTypeface(currentTypeface), return new ShapeableTextCharacters(text.Take(count), defaultProperties.WithTypeface(currentTypeface),
biDiLevel); biDiLevel);
} }
if (previousTypeface is not null) if (previousTypeface is not null)
{ {
if(TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out count, out _)) if (TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out count, out _))
{ {
return new ShapeableTextCharacters(text.Take(count), return new ShapeableTextCharacters(text.Take(count),
defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel); defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel);
@ -106,12 +106,12 @@ namespace Avalonia.Media.TextFormatting
{ {
continue; continue;
} }
codepoint = codepointEnumerator.Current; codepoint = codepointEnumerator.Current;
break; break;
} }
//ToDo: Fix FontFamily fallback //ToDo: Fix FontFamily fallback
var matchFound = var matchFound =
FontManager.Current.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight, FontManager.Current.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight,
@ -157,14 +157,14 @@ namespace Avalonia.Media.TextFormatting
/// <param name="script"></param> /// <param name="script"></param>
/// <returns></returns> /// <returns></returns>
protected static bool TryGetShapeableLength( protected static bool TryGetShapeableLength(
ReadOnlySlice<char> text, ReadOnlySlice<char> text,
Typeface typeface, Typeface typeface,
Typeface? defaultTypeface, Typeface? defaultTypeface,
out int length, out int length,
out Script script) out Script script)
{ {
length = 0; length = 0;
script = Script.Unknown; script = Script.Unknown;
if (text.Length == 0) if (text.Length == 0)
{ {
@ -182,7 +182,7 @@ namespace Avalonia.Media.TextFormatting
var currentScript = currentGrapheme.FirstCodepoint.Script; var currentScript = currentGrapheme.FirstCodepoint.Script;
if (currentScript != Script.Common && defaultFont != null && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) if (!currentGrapheme.FirstCodepoint.IsWhiteSpace && defaultFont != null && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _))
{ {
break; break;
} }
@ -192,7 +192,7 @@ namespace Avalonia.Media.TextFormatting
{ {
break; break;
} }
if (currentScript != script) if (currentScript != script)
{ {
if (script is Script.Unknown || currentScript != Script.Common && if (script is Script.Unknown || currentScript != Script.Common &&

58
src/Avalonia.Base/Media/TextFormatting/TextLayout.cs

@ -63,7 +63,7 @@ namespace Avalonia.Media.TextFormatting
MaxHeight = maxHeight; MaxHeight = maxHeight;
MaxLines = maxLines; MaxLines = maxLines;
TextLines = CreateTextLines(); TextLines = CreateTextLines();
} }
@ -80,7 +80,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="maxLines">The maximum number of text lines.</param> /// <param name="maxLines">The maximum number of text lines.</param>
public TextLayout( public TextLayout(
ITextSource textSource, ITextSource textSource,
TextParagraphProperties paragraphProperties, TextParagraphProperties paragraphProperties,
TextTrimming? textTrimming = null, TextTrimming? textTrimming = null,
double maxWidth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity,
double maxHeight = double.PositiveInfinity, double maxHeight = double.PositiveInfinity,
@ -178,24 +178,18 @@ namespace Avalonia.Media.TextFormatting
return new Rect(); return new Rect();
} }
if (textPosition < 0 || textPosition >= _textSourceLength) if (textPosition < 0)
{ {
var lastLine = TextLines[TextLines.Count - 1]; textPosition = _textSourceLength;
var lineX = lastLine.Width;
var lineY = Bounds.Bottom - lastLine.Height;
return new Rect(lineX, lineY, 0, lastLine.Height);
} }
var currentY = 0.0; var currentY = 0.0;
foreach (var textLine in TextLines) foreach (var textLine in TextLines)
{ {
var end = textLine.FirstTextSourceIndex + textLine.Length - 1; var end = textLine.FirstTextSourceIndex + textLine.Length;
if (end < textPosition) if (end <= textPosition && end < _textSourceLength)
{ {
currentY += textLine.Height; currentY += textLine.Height;
@ -224,7 +218,7 @@ namespace Avalonia.Media.TextFormatting
} }
var result = new List<Rect>(TextLines.Count); var result = new List<Rect>(TextLines.Count);
var currentY = 0d; var currentY = 0d;
foreach (var textLine in TextLines) foreach (var textLine in TextLines)
@ -239,7 +233,7 @@ namespace Avalonia.Media.TextFormatting
var textBounds = textLine.GetTextBounds(start, length); var textBounds = textLine.GetTextBounds(start, length);
if(textBounds.Count > 0) if (textBounds.Count > 0)
{ {
foreach (var bounds in textBounds) foreach (var bounds in textBounds)
{ {
@ -262,7 +256,7 @@ namespace Avalonia.Media.TextFormatting
} }
} }
if(textLine.FirstTextSourceIndex + textLine.Length >= start + length) if (textLine.FirstTextSourceIndex + textLine.Length >= start + length)
{ {
break; break;
} }
@ -305,7 +299,7 @@ namespace Avalonia.Media.TextFormatting
return GetHitTestResult(currentLine, characterHit, point); return GetHitTestResult(currentLine, characterHit, point);
} }
public int GetLineIndexFromCharacterIndex(int charIndex, bool trailingEdge) public int GetLineIndexFromCharacterIndex(int charIndex, bool trailingEdge)
{ {
if (charIndex < 0) if (charIndex < 0)
@ -327,7 +321,7 @@ namespace Avalonia.Media.TextFormatting
continue; continue;
} }
if (charIndex >= textLine.FirstTextSourceIndex && if (charIndex >= textLine.FirstTextSourceIndex &&
charIndex <= textLine.FirstTextSourceIndex + textLine.Length - (trailingEdge ? 0 : 1)) charIndex <= textLine.FirstTextSourceIndex + textLine.Length - (trailingEdge ? 0 : 1))
{ {
return index; return index;
@ -398,7 +392,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="left">The current left.</param> /// <param name="left">The current left.</param>
/// <param name="width">The current width.</param> /// <param name="width">The current width.</param>
/// <param name="height">The current height.</param> /// <param name="height">The current height.</param>
private static void UpdateBounds(TextLine textLine,ref double left, ref double width, ref double height) private static void UpdateBounds(TextLine textLine, ref double left, ref double width, ref double height)
{ {
var lineWidth = textLine.WidthIncludingTrailingWhitespace; var lineWidth = textLine.WidthIncludingTrailingWhitespace;
@ -421,7 +415,7 @@ namespace Avalonia.Media.TextFormatting
{ {
var textLine = TextFormatterImpl.CreateEmptyTextLine(0, double.PositiveInfinity, _paragraphProperties); var textLine = TextFormatterImpl.CreateEmptyTextLine(0, double.PositiveInfinity, _paragraphProperties);
Bounds = new Rect(0,0,0, textLine.Height); Bounds = new Rect(0, 0, 0, textLine.Height);
return new List<TextLine> { textLine }; return new List<TextLine> { textLine };
} }
@ -439,9 +433,9 @@ namespace Avalonia.Media.TextFormatting
var textLine = TextFormatter.Current.FormatLine(_textSource, _textSourceLength, MaxWidth, var textLine = TextFormatter.Current.FormatLine(_textSource, _textSourceLength, MaxWidth,
_paragraphProperties, previousLine?.TextLineBreak); _paragraphProperties, previousLine?.TextLineBreak);
if(textLine == null || textLine.Length == 0 || textLine.TextRuns.Count == 0 && textLine.TextLineBreak?.TextEndOfLine is TextEndOfParagraph) if (textLine == null || textLine.Length == 0 || textLine.TextRuns.Count == 0 && textLine.TextLineBreak?.TextEndOfLine is TextEndOfParagraph)
{ {
if(previousLine != null && previousLine.NewLineLength > 0) if (previousLine != null && previousLine.NewLineLength > 0)
{ {
var emptyTextLine = TextFormatterImpl.CreateEmptyTextLine(_textSourceLength, MaxWidth, _paragraphProperties); var emptyTextLine = TextFormatterImpl.CreateEmptyTextLine(_textSourceLength, MaxWidth, _paragraphProperties);
@ -454,7 +448,7 @@ namespace Avalonia.Media.TextFormatting
} }
_textSourceLength += textLine.Length; _textSourceLength += textLine.Length;
//Fulfill max height constraint //Fulfill max height constraint
if (textLines.Count > 0 && !double.IsPositiveInfinity(MaxHeight) && height + textLine.Height > MaxHeight) if (textLines.Count > 0 && !double.IsPositiveInfinity(MaxHeight) && height + textLine.Height > MaxHeight)
{ {
@ -485,12 +479,17 @@ namespace Avalonia.Media.TextFormatting
//Fulfill max lines constraint //Fulfill max lines constraint
if (MaxLines > 0 && textLines.Count >= MaxLines) if (MaxLines > 0 && textLines.Count >= MaxLines)
{ {
if(textLine.TextLineBreak is TextLineBreak lineBreak && lineBreak.RemainingRuns != null)
{
textLines[textLines.Count - 1] = textLine.Collapse(GetCollapsingProperties(width));
}
break; break;
} }
} }
//Make sure the TextLayout always contains at least on empty line //Make sure the TextLayout always contains at least on empty line
if(textLines.Count == 0) if (textLines.Count == 0)
{ {
var textLine = TextFormatterImpl.CreateEmptyTextLine(0, MaxWidth, _paragraphProperties); var textLine = TextFormatterImpl.CreateEmptyTextLine(0, MaxWidth, _paragraphProperties);
@ -501,7 +500,7 @@ namespace Avalonia.Media.TextFormatting
Bounds = new Rect(left, 0, width, height); Bounds = new Rect(left, 0, width, height);
if(_paragraphProperties.TextAlignment == TextAlignment.Justify) if (_paragraphProperties.TextAlignment == TextAlignment.Justify)
{ {
var whitespaceWidth = 0d; var whitespaceWidth = 0d;
@ -509,7 +508,7 @@ namespace Avalonia.Media.TextFormatting
{ {
var lineWhitespaceWidth = line.Width - line.WidthIncludingTrailingWhitespace; var lineWhitespaceWidth = line.Width - line.WidthIncludingTrailingWhitespace;
if(lineWhitespaceWidth > whitespaceWidth) if (lineWhitespaceWidth > whitespaceWidth)
{ {
whitespaceWidth = lineWhitespaceWidth; whitespaceWidth = lineWhitespaceWidth;
} }
@ -517,7 +516,7 @@ namespace Avalonia.Media.TextFormatting
var justificationWidth = width - whitespaceWidth; var justificationWidth = width - whitespaceWidth;
if(justificationWidth > 0) if (justificationWidth > 0)
{ {
var justificationProperties = new InterWordJustification(justificationWidth); var justificationProperties = new InterWordJustification(justificationWidth);
@ -538,8 +537,13 @@ namespace Avalonia.Media.TextFormatting
/// </summary> /// </summary>
/// <param name="width">The collapsing width.</param> /// <param name="width">The collapsing width.</param>
/// <returns>The <see cref="TextCollapsingProperties"/>.</returns> /// <returns>The <see cref="TextCollapsingProperties"/>.</returns>
private TextCollapsingProperties GetCollapsingProperties(double width) private TextCollapsingProperties? GetCollapsingProperties(double width)
{ {
if(_textTrimming == TextTrimming.None)
{
return null;
}
return _textTrimming.CreateCollapsingProperties(new TextCollapsingCreateInfo(width, _paragraphProperties.DefaultTextRunProperties)); return _textTrimming.CreateCollapsingProperties(new TextCollapsingCreateInfo(width, _paragraphProperties.DefaultTextRunProperties));
} }
} }

2
src/Avalonia.Base/Media/TextFormatting/TextLine.cs

@ -153,7 +153,7 @@ namespace Avalonia.Media.TextFormatting
/// <returns> /// <returns>
/// A <see cref="TextLine"/> value that represents a collapsed line that can be displayed. /// A <see cref="TextLine"/> value that represents a collapsed line that can be displayed.
/// </returns> /// </returns>
public abstract TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList); public abstract TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList);
/// <summary> /// <summary>
/// Create a justified line based on justification text properties. /// Create a justified line based on justification text properties.

737
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -119,7 +119,7 @@ namespace Avalonia.Media.TextFormatting
} }
/// <inheritdoc/> /// <inheritdoc/>
public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) public override TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList)
{ {
if (collapsingPropertiesList.Length == 0) if (collapsingPropertiesList.Length == 0)
{ {
@ -128,6 +128,11 @@ namespace Avalonia.Media.TextFormatting
var collapsingProperties = collapsingPropertiesList[0]; var collapsingProperties = collapsingPropertiesList[0];
if(collapsingProperties is null)
{
return this;
}
var collapsedRuns = collapsingProperties.Collapse(this); var collapsedRuns = collapsingProperties.Collapse(this);
if (collapsedRuns is null) if (collapsedRuns is null)
@ -166,58 +171,122 @@ namespace Avalonia.Media.TextFormatting
if (distance <= 0) if (distance <= 0)
{ {
// hit happens before the line, return the first position
var firstRun = _textRuns[0]; var firstRun = _textRuns[0];
if (firstRun is ShapedTextCharacters shapedTextCharacters) return GetRunCharacterHit(firstRun, FirstTextSourceIndex, 0);
{ }
return shapedTextCharacters.GlyphRun.GetCharacterHitFromDistance(distance, out _);
}
return _resolvedFlowDirection == FlowDirection.LeftToRight ? if (distance >= WidthIncludingTrailingWhitespace)
new CharacterHit(FirstTextSourceIndex) : {
new CharacterHit(FirstTextSourceIndex + Length); var lastRun = _textRuns[_textRuns.Count - 1];
return GetRunCharacterHit(lastRun, FirstTextSourceIndex + Length - lastRun.TextSourceLength, lastRun.Size.Width);
} }
// process hit that happens within the line // process hit that happens within the line
var characterHit = new CharacterHit(); var characterHit = new CharacterHit();
var currentPosition = FirstTextSourceIndex; var currentPosition = FirstTextSourceIndex;
var currentDistance = 0.0;
foreach (var currentRun in _textRuns) for (var i = 0; i < _textRuns.Count; i++)
{ {
switch (currentRun) var currentRun = _textRuns[i];
if(currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight)
{ {
case ShapedTextCharacters shapedRun: var rightToLeftIndex = i;
currentPosition += currentRun.TextSourceLength;
while (rightToLeftIndex + 1 <= _textRuns.Count - 1)
{
var nextShaped = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters;
if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight)
{ {
characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); break;
}
var offset = Math.Max(0, currentPosition - shapedRun.Text.Start); currentPosition += nextShaped.TextSourceLength;
characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); rightToLeftIndex++;
}
for (var j = i; i <= rightToLeftIndex; j++)
{
if(j > _textRuns.Count - 1)
{
break; break;
} }
default:
currentRun = _textRuns[j];
if(currentDistance + currentRun.Size.Width <= distance)
{ {
if (distance < currentRun.Size.Width / 2) currentDistance += currentRun.Size.Width;
{ currentPosition -= currentRun.TextSourceLength;
characterHit = new CharacterHit(currentPosition);
} continue;
else
{
characterHit = new CharacterHit(currentPosition, currentRun.TextSourceLength);
}
break;
} }
characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
break;
}
} }
if (distance <= currentRun.Size.Width) if (currentDistance + currentRun.Size.Width < distance)
{ {
break; currentDistance += currentRun.Size.Width;
currentPosition += currentRun.TextSourceLength;
continue;
} }
distance -= currentRun.Size.Width; characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
currentPosition += currentRun.TextSourceLength;
break;
}
return characterHit;
}
private static CharacterHit GetRunCharacterHit(DrawableTextRun run, int currentPosition, double distance)
{
CharacterHit characterHit;
switch (run)
{
case ShapedTextCharacters shapedRun:
{
characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _);
var offset = 0;
if (shapedRun.GlyphRun.IsLeftToRight)
{
offset = Math.Max(0, currentPosition - shapedRun.Text.Start);
}
//else
//{
// offset = Math.Max(0, currentPosition - shapedRun.Text.Start + shapedRun.Text.Length);
//}
characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength);
break;
}
default:
{
if (distance < run.Size.Width / 2)
{
characterHit = new CharacterHit(currentPosition);
}
else
{
characterHit = new CharacterHit(currentPosition, run.TextSourceLength);
}
break;
}
} }
return characterHit; return characterHit;
@ -226,136 +295,168 @@ namespace Avalonia.Media.TextFormatting
/// <inheritdoc/> /// <inheritdoc/>
public override double GetDistanceFromCharacterHit(CharacterHit characterHit) public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
{ {
var isTrailingHit = characterHit.TrailingLength > 0; var flowDirection = _paragraphProperties.FlowDirection;
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
var currentDistance = Start;
var currentPosition = FirstTextSourceIndex; var currentPosition = FirstTextSourceIndex;
var remainingLength = characterIndex - FirstTextSourceIndex; var remainingLength = characterIndex - FirstTextSourceIndex;
GlyphRun? lastRun = null; var currentDistance = Start;
for (var index = 0; index < _textRuns.Count; index++) if (flowDirection == FlowDirection.LeftToRight)
{ {
var textRun = _textRuns[index]; for (var index = 0; index < _textRuns.Count; index++)
switch (textRun)
{ {
case ShapedTextCharacters shapedTextCharacters: var currentRun = _textRuns[index];
{
var currentRun = shapedTextCharacters.GlyphRun;
if (lastRun != null) if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight)
{ {
if (!lastRun.IsLeftToRight && currentRun.IsLeftToRight && var i = index;
currentRun.Characters.Start == characterHit.FirstCharacterIndex &&
characterHit.TrailingLength == 0) var rightToLeftWidth = currentRun.Size.Width;
{
return currentDistance;
}
}
//Look for a hit in within the current run while (i + 1 <= _textRuns.Count - 1)
if (currentPosition + remainingLength <= currentPosition + textRun.Text.Length) {
var nextRun = _textRuns[i + 1];
if (nextRun is ShapedTextCharacters nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight)
{ {
characterHit = new CharacterHit(textRun.Text.Start + remainingLength); i++;
var distance = currentRun.GetDistanceFromCharacterHit(characterHit); rightToLeftWidth += nextRun.Size.Width;
return currentDistance + distance; continue;
} }
break;
}
//Look at the left and right edge of the current run if(i > index)
if (currentRun.IsLeftToRight) {
while (i >= index)
{ {
if (_resolvedFlowDirection == FlowDirection.LeftToRight && (lastRun == null || lastRun.IsLeftToRight)) currentRun = _textRuns[i];
{
if (characterIndex <= currentPosition)
{
return currentDistance;
}
}
else
{
if (characterIndex == currentPosition)
{
return currentDistance;
}
}
if (characterIndex == currentPosition + textRun.Text.Length && isTrailingHit) rightToLeftWidth -= currentRun.Size.Width;
{
return currentDistance + currentRun.Size.Width; if (currentPosition + currentRun.TextSourceLength >= characterIndex)
}
}
else
{
if (characterIndex == currentPosition)
{ {
return currentDistance + currentRun.Size.Width; break;
} }
var nextRun = index + 1 < _textRuns.Count ? currentPosition += currentRun.TextSourceLength;
_textRuns[index + 1] as ShapedTextCharacters :
null;
if (nextRun != null) remainingLength -= currentRun.TextSourceLength;
{
if (nextRun.ShapedBuffer.IsLeftToRight) i--;
{
if (characterIndex == currentPosition + textRun.Text.Length)
{
return currentDistance;
}
}
else
{
if (currentPosition + nextRun.Text.Length == characterIndex)
{
return currentDistance;
}
}
}
else
{
if (characterIndex > currentPosition + textRun.Text.Length)
{
return currentDistance;
}
}
} }
lastRun = currentRun; currentDistance += rightToLeftWidth;
}
}
if (currentPosition + currentRun.TextSourceLength >= characterIndex &&
TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, flowDirection, out var distance, out _))
{
return Math.Max(0, currentDistance + distance);
}
break; //No hit hit found so we add the full width
currentDistance += currentRun.Size.Width;
currentPosition += currentRun.TextSourceLength;
remainingLength -= currentRun.TextSourceLength;
}
}
else
{
currentDistance += WidthIncludingTrailingWhitespace;
for (var index = _textRuns.Count - 1; index >= 0; index--)
{
var currentRun = _textRuns[index];
if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength,
flowDirection, out var distance, out var currentGlyphRun))
{
if (currentGlyphRun != null)
{
distance = currentGlyphRun.Size.Width - distance;
} }
default:
return Math.Max(0, currentDistance - distance);
}
//No hit hit found so we add the full width
currentDistance -= currentRun.Size.Width;
currentPosition += currentRun.TextSourceLength;
remainingLength -= currentRun.TextSourceLength;
}
}
return Math.Max(0, currentDistance);
}
private static bool TryGetDistanceFromCharacterHit(
DrawableTextRun currentRun,
CharacterHit characterHit,
int currentPosition,
int remainingLength,
FlowDirection flowDirection,
out double distance,
out GlyphRun? currentGlyphRun)
{
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
var isTrailingHit = characterHit.TrailingLength > 0;
distance = 0;
currentGlyphRun = null;
switch (currentRun)
{
case ShapedTextCharacters shapedTextCharacters:
{
currentGlyphRun = shapedTextCharacters.GlyphRun;
if (currentPosition + remainingLength <= currentPosition + currentRun.Text.Length)
{ {
if (characterIndex == currentPosition) characterHit = new CharacterHit(currentRun.Text.Start + remainingLength);
{
return currentDistance; distance = currentGlyphRun.GetDistanceFromCharacterHit(characterHit);
}
return true;
}
if (characterIndex == currentPosition + textRun.TextSourceLength) if (currentPosition + remainingLength == currentPosition + currentRun.Text.Length && isTrailingHit)
{
if (currentGlyphRun.IsLeftToRight || flowDirection == FlowDirection.RightToLeft)
{ {
return currentDistance + textRun.Size.Width; distance = currentGlyphRun.Size.Width;
} }
break; return true;
} }
}
//No hit hit found so we add the full width break;
currentDistance += textRun.Size.Width; }
currentPosition += textRun.TextSourceLength; default:
remainingLength -= textRun.TextSourceLength; {
if (characterIndex == currentPosition)
{
return true;
}
if (remainingLength <= 0) if (characterIndex == currentPosition + currentRun.TextSourceLength)
{ {
break; distance = currentRun.Size.Width;
}
return true;
}
break;
}
} }
return currentDistance; return false;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -440,121 +541,168 @@ namespace Avalonia.Media.TextFormatting
continue; continue;
} }
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
{
startX += currentRun.Size.Width;
currentPosition += currentRun.TextSourceLength;
continue;
}
var characterLength = 0; var characterLength = 0;
var endX = startX; var endX = startX;
var runWidth = 0.0;
TextRunBounds? currentRunBounds = null;
if (currentRun is ShapedTextCharacters currentShapedRun) var currentShapedRun = currentRun as ShapedTextCharacters;
{
var offset = Math.Max(0, firstTextSourceIndex - currentPosition);
currentPosition += offset;
var startIndex = currentRun.Text.Start + offset; if (currentShapedRun != null && !currentShapedRun.ShapedBuffer.IsLeftToRight)
{
var rightToLeftIndex = index;
startX += currentShapedRun.Size.Width;
var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( while (rightToLeftIndex + 1 <= _textRuns.Count - 1)
currentShapedRun.ShapedBuffer.IsLeftToRight ? {
new CharacterHit(startIndex + remainingLength) : var nextShapedRun = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters;
new CharacterHit(startIndex));
endX += endOffset; if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight)
{
break;
}
var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( startX += nextShapedRun.Size.Width;
currentShapedRun.ShapedBuffer.IsLeftToRight ?
new CharacterHit(startIndex) :
new CharacterHit(startIndex + remainingLength));
startX += startOffset; rightToLeftIndex++;
}
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); if (TryGetTextRunBoundsRightToLeft(startX, firstTextSourceIndex, characterIndex, rightToLeftIndex, ref currentPosition, ref remainingLength, out currentRunBounds))
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); {
startX = currentRunBounds!.Rectangle.Left;
endX = currentRunBounds.Rectangle.Right;
characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); runWidth = currentRunBounds.Rectangle.Width;
}
currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? currentDirection = FlowDirection.RightToLeft;
FlowDirection.LeftToRight :
FlowDirection.RightToLeft;
} }
else else
{ {
if (currentPosition < firstTextSourceIndex) if (currentShapedRun != null)
{ {
startX += currentRun.Size.Width; if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
} {
startX += currentRun.Size.Width;
if (currentPosition + currentRun.TextSourceLength <= characterIndex) currentPosition += currentRun.TextSourceLength;
{
endX += currentRun.Size.Width;
characterLength = currentRun.TextSourceLength; continue;
}
var offset = Math.Max(0, firstTextSourceIndex - currentPosition);
currentPosition += offset;
var startIndex = currentRun.Text.Start + offset;
double startOffset;
double endOffset;
if (currentShapedRun.ShapedBuffer.IsLeftToRight)
{
startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
}
else
{
endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
if (currentPosition < startIndex)
{
startOffset = endOffset;
}
else
{
startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
}
}
startX += startOffset;
endX += endOffset;
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength);
currentDirection = FlowDirection.LeftToRight;
} }
} else
{
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
{
startX += currentRun.Size.Width;
if (endX < startX) currentPosition += currentRun.TextSourceLength;
{
(endX, startX) = (startX, endX);
}
//Lines that only contain a linebreak need to be covered here continue;
if(characterLength == 0) }
{
characterLength = NewLineLength;
}
var runwidth = endX - startX; if (currentPosition < firstTextSourceIndex)
var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runwidth, Height), currentPosition, characterLength, currentRun); {
startX += currentRun.Size.Width;
}
if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) if (currentPosition + currentRun.TextSourceLength <= characterIndex)
{ {
currentRect = currentRect.WithWidth(currentWidth + runwidth); endX += currentRun.Size.Width;
var textBounds = result[result.Count - 1]; characterLength = currentRun.TextSourceLength;
}
}
textBounds.Rectangle = currentRect; if (endX < startX)
{
(endX, startX) = (startX, endX);
}
textBounds.TextRunBounds.Add(currentRunBounds); //Lines that only contain a linebreak need to be covered here
} if (characterLength == 0)
else {
{ characterLength = NewLineLength;
currentRect = currentRunBounds.Rectangle; }
result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); runWidth = endX - startX;
} currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
currentWidth += runwidth; currentPosition += characterLength;
currentPosition += characterLength;
remainingLength -= characterLength;
}
if (currentDirection == FlowDirection.LeftToRight) if (currentRunBounds != null && !MathUtilities.IsZero(runWidth) || NewLineLength > 0)
{ {
if (currentPosition > characterIndex) if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX))
{ {
break; currentRect = currentRect.WithWidth(currentWidth + runWidth);
var textBounds = result[result.Count - 1];
textBounds.Rectangle = currentRect;
textBounds.TextRunBounds.Add(currentRunBounds!);
} }
} else
else
{
if (currentPosition <= firstTextSourceIndex)
{ {
break; currentRect = currentRunBounds!.Rectangle;
result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds }));
} }
} }
startX = endX; currentWidth += runWidth;
lastDirection = currentDirection;
remainingLength -= characterLength;
if (remainingLength <= 0) if (remainingLength <= 0 || currentPosition >= characterIndex)
{ {
break; break;
} }
startX = endX;
lastDirection = currentDirection;
} }
return result; return result;
@ -571,7 +719,7 @@ namespace Avalonia.Media.TextFormatting
var currentPosition = FirstTextSourceIndex; var currentPosition = FirstTextSourceIndex;
var remainingLength = textLength; var remainingLength = textLength;
var startX = Start + WidthIncludingTrailingWhitespace; var startX = WidthIncludingTrailingWhitespace;
double currentWidth = 0; double currentWidth = 0;
var currentRect = Rect.Empty; var currentRect = Rect.Empty;
@ -582,7 +730,7 @@ namespace Avalonia.Media.TextFormatting
continue; continue;
} }
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) if (currentPosition + currentRun.TextSourceLength < firstTextSourceIndex)
{ {
startX -= currentRun.Size.Width; startX -= currentRun.Size.Width;
@ -601,20 +749,31 @@ namespace Avalonia.Media.TextFormatting
currentPosition += offset; currentPosition += offset;
var startIndex = currentRun.Text.Start + offset; var startIndex = currentRun.Text.Start + offset;
double startOffset;
double endOffset;
var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( if (currentShapedRun.ShapedBuffer.IsLeftToRight)
currentShapedRun.ShapedBuffer.IsLeftToRight ? {
new CharacterHit(startIndex + remainingLength) : if (currentPosition < startIndex)
new CharacterHit(startIndex)); {
startOffset = endOffset = 0;
}
else
{
endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
endX += endOffset - currentShapedRun.Size.Width; startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
}
}
else
{
endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
currentShapedRun.ShapedBuffer.IsLeftToRight ? }
new CharacterHit(startIndex) :
new CharacterHit(startIndex + remainingLength));
startX += startOffset - currentShapedRun.Size.Width; startX -= currentRun.Size.Width - startOffset;
endX -= currentRun.Size.Width - endOffset;
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
@ -652,53 +811,150 @@ namespace Avalonia.Media.TextFormatting
} }
var runWidth = endX - startX; var runWidth = endX - startX;
var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) var currentRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
if (!MathUtilities.IsZero(runWidth) || NewLineLength > 0)
{ {
currentRect = currentRect.WithWidth(currentWidth + runWidth); if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, Start + startX))
{
currentRect = currentRect.WithWidth(currentWidth + runWidth);
var textBounds = result[result.Count - 1]; var textBounds = result[result.Count - 1];
textBounds.Rectangle = currentRect; textBounds.Rectangle = currentRect;
textBounds.TextRunBounds.Add(currentRunBounds); textBounds.TextRunBounds.Add(currentRunBounds);
} }
else else
{ {
currentRect = currentRunBounds.Rectangle; currentRect = currentRunBounds.Rectangle;
result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds }));
}
} }
currentWidth += runWidth; currentWidth += runWidth;
currentPosition += characterLength; currentPosition += characterLength;
if (currentDirection == FlowDirection.LeftToRight) if (currentPosition > characterIndex)
{
break;
}
lastDirection = currentDirection;
remainingLength -= characterLength;
if (remainingLength <= 0)
{
break;
}
}
result.Reverse();
return result;
}
private bool TryGetTextRunBoundsRightToLeft(double startX, int firstTextSourceIndex, int characterIndex, int runIndex, ref int currentPosition, ref int remainingLength, out TextRunBounds? textRunBounds)
{
textRunBounds = null;
for (var index = runIndex; index >= 0; index--)
{
if (TextRuns[index] is not DrawableTextRun currentRun)
{
continue;
}
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
{ {
if (currentPosition > characterIndex) startX -= currentRun.Size.Width;
currentPosition += currentRun.TextSourceLength;
continue;
}
var characterLength = 0;
var endX = startX;
if (currentRun is ShapedTextCharacters currentShapedRun)
{
var offset = Math.Max(0, firstTextSourceIndex - currentPosition);
currentPosition += offset;
var startIndex = currentRun.Text.Start + offset;
double startOffset;
double endOffset;
if (currentShapedRun.ShapedBuffer.IsLeftToRight)
{ {
break; if (currentPosition < startIndex)
{
startOffset = endOffset = 0;
}
else
{
endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
}
} }
else
{
endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
}
startX -= currentRun.Size.Width - startOffset;
endX -= currentRun.Size.Width - endOffset;
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength);
} }
else else
{ {
if (currentPosition <= firstTextSourceIndex) if (currentPosition + currentRun.TextSourceLength <= characterIndex)
{ {
break; endX -= currentRun.Size.Width;
}
if (currentPosition < firstTextSourceIndex)
{
startX -= currentRun.Size.Width;
characterLength = currentRun.TextSourceLength;
} }
} }
lastDirection = currentDirection; if (endX < startX)
remainingLength -= characterLength; {
(endX, startX) = (startX, endX);
}
if (remainingLength <= 0) //Lines that only contain a linebreak need to be covered here
if (characterLength == 0)
{ {
break; characterLength = NewLineLength;
} }
var runWidth = endX - startX;
remainingLength -= characterLength;
currentPosition += characterLength;
textRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
return true;
} }
return result; return false;
} }
public override IReadOnlyList<TextBounds> GetTextBounds(int firstTextSourceIndex, int textLength) public override IReadOnlyList<TextBounds> GetTextBounds(int firstTextSourceIndex, int textLength)
@ -1280,6 +1536,11 @@ namespace Avalonia.Media.TextFormatting
var textAlignment = _paragraphProperties.TextAlignment; var textAlignment = _paragraphProperties.TextAlignment;
var paragraphFlowDirection = _paragraphProperties.FlowDirection; var paragraphFlowDirection = _paragraphProperties.FlowDirection;
if(textAlignment == TextAlignment.Justify)
{
textAlignment = TextAlignment.Start;
}
switch (textAlignment) switch (textAlignment)
{ {
case TextAlignment.Start: case TextAlignment.Start:
@ -1302,8 +1563,14 @@ namespace Avalonia.Media.TextFormatting
switch (textAlignment) switch (textAlignment)
{ {
case TextAlignment.Center: case TextAlignment.Center:
return Math.Max(0, (_paragraphWidth - width) / 2); var start = (_paragraphWidth - width) / 2;
if (paragraphFlowDirection == FlowDirection.RightToLeft)
{
start -= (widthIncludingTrailingWhitespace - width);
}
return Math.Max(0, start);
case TextAlignment.Right: case TextAlignment.Right:
return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace); return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace);

2
src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs

@ -224,7 +224,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
} }
/// <summary> /// <summary>
/// Returns <see langword="true"/> if <paramref name="value"/> is between /// Returns <see langword="true"/> if <paramref name="cp"/> is between
/// <paramref name="lowerBound"/> and <paramref name="upperBound"/>, inclusive. /// <paramref name="lowerBound"/> and <paramref name="upperBound"/>, inclusive.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

4
src/Avalonia.Base/Platform/IGeometryImpl.cs

@ -38,8 +38,8 @@ namespace Avalonia.Platform
/// Intersects the geometry with another geometry. /// Intersects the geometry with another geometry.
/// </summary> /// </summary>
/// <param name="geometry">The other geometry.</param> /// <param name="geometry">The other geometry.</param>
/// <returns>A new <see cref="IGeometryImpl"/> representing the intersection.</returns> /// <returns>A new <see cref="IGeometryImpl"/> representing the intersection or <c>null</c> when the operation failed.</returns>
IGeometryImpl Intersect(IGeometryImpl geometry); IGeometryImpl? Intersect(IGeometryImpl geometry);
/// <summary> /// <summary>
/// Indicates whether the geometry's stroke contains the specified point. /// Indicates whether the geometry's stroke contains the specified point.

8
src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs

@ -47,22 +47,22 @@ public class BclStorageFile : IStorageBookmarkFile
return Task.FromResult<IStorageFolder?>(null); return Task.FromResult<IStorageFolder?>(null);
} }
public Task<Stream> OpenRead() public Task<Stream> OpenReadAsync()
{ {
return Task.FromResult<Stream>(_fileInfo.OpenRead()); return Task.FromResult<Stream>(_fileInfo.OpenRead());
} }
public Task<Stream> OpenWrite() public Task<Stream> OpenWriteAsync()
{ {
return Task.FromResult<Stream>(_fileInfo.OpenWrite()); return Task.FromResult<Stream>(_fileInfo.OpenWrite());
} }
public virtual Task<string?> SaveBookmark() public virtual Task<string?> SaveBookmarkAsync()
{ {
return Task.FromResult<string?>(_fileInfo.FullName); return Task.FromResult<string?>(_fileInfo.FullName);
} }
public Task ReleaseBookmark() public Task ReleaseBookmarkAsync()
{ {
// No-op // No-op
return Task.CompletedTask; return Task.CompletedTask;

16
src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq;
using System.Security; using System.Security;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Metadata; using Avalonia.Metadata;
@ -43,12 +45,22 @@ public class BclStorageFolder : IStorageBookmarkFolder
return Task.FromResult<IStorageFolder?>(null); return Task.FromResult<IStorageFolder?>(null);
} }
public virtual Task<string?> SaveBookmark() public Task<IReadOnlyList<IStorageItem>> GetItemsAsync()
{
var items = _directoryInfo.GetDirectories()
.Select(d => (IStorageItem)new BclStorageFolder(d))
.Concat(_directoryInfo.GetFiles().Select(f => new BclStorageFile(f)))
.ToArray();
return Task.FromResult<IReadOnlyList<IStorageItem>>(items);
}
public virtual Task<string?> SaveBookmarkAsync()
{ {
return Task.FromResult<string?>(_directoryInfo.FullName); return Task.FromResult<string?>(_directoryInfo.FullName);
} }
public Task ReleaseBookmark() public Task ReleaseBookmarkAsync()
{ {
// No-op // No-op
return Task.CompletedTask; return Task.CompletedTask;

2
src/Avalonia.Base/Platform/Storage/IStorageBookmarkItem.cs

@ -6,7 +6,7 @@ namespace Avalonia.Platform.Storage;
[NotClientImplementable] [NotClientImplementable]
public interface IStorageBookmarkItem : IStorageItem public interface IStorageBookmarkItem : IStorageItem
{ {
Task ReleaseBookmark(); Task ReleaseBookmarkAsync();
} }
[NotClientImplementable] [NotClientImplementable]

4
src/Avalonia.Base/Platform/Storage/IStorageFile.cs

@ -18,7 +18,7 @@ public interface IStorageFile : IStorageItem
/// <summary> /// <summary>
/// Opens a stream for read access. /// Opens a stream for read access.
/// </summary> /// </summary>
Task<Stream> OpenRead(); Task<Stream> OpenReadAsync();
/// <summary> /// <summary>
/// Returns true, if file is writeable. /// Returns true, if file is writeable.
@ -28,5 +28,5 @@ public interface IStorageFile : IStorageItem
/// <summary> /// <summary>
/// Opens stream for writing to the file. /// Opens stream for writing to the file.
/// </summary> /// </summary>
Task<Stream> OpenWrite(); Task<Stream> OpenWriteAsync();
} }

11
src/Avalonia.Base/Platform/Storage/IStorageFolder.cs

@ -1,4 +1,6 @@
using Avalonia.Metadata; using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Metadata;
namespace Avalonia.Platform.Storage; namespace Avalonia.Platform.Storage;
@ -8,4 +10,11 @@ namespace Avalonia.Platform.Storage;
[NotClientImplementable] [NotClientImplementable]
public interface IStorageFolder : IStorageItem public interface IStorageFolder : IStorageItem
{ {
/// <summary>
/// Gets the files and subfolders in the current folder.
/// </summary>
/// <returns>
/// When this method completes successfully, it returns a list of the files and folders in the current folder. Each item in the list is represented by an <see cref="IStorageItem"/> implementation object.
/// </returns>
Task<IReadOnlyList<IStorageItem>> GetItemsAsync();
} }

2
src/Avalonia.Base/Platform/Storage/IStorageItem.cs

@ -44,7 +44,7 @@ public interface IStorageItem : IDisposable
/// <returns> /// <returns>
/// Returns identifier of a bookmark. Can be null if OS denied request. /// Returns identifier of a bookmark. Can be null if OS denied request.
/// </returns> /// </returns>
Task<string?> SaveBookmark(); Task<string?> SaveBookmarkAsync();
/// <summary> /// <summary>
/// Gets the parent folder of the current storage item. /// Gets the parent folder of the current storage item.

5
src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs

@ -3,8 +3,9 @@ using System.Collections.Generic;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations; // Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations;
/// <summary> /// <summary>
/// The base class for both key-frame and expression animation instances /// The base class for both key-frame and expression animation instances
@ -79,4 +80,4 @@ internal abstract class AnimationInstanceBase : IAnimationInstance
_invalidated = true; _invalidated = true;
TargetObject.NotifyAnimatedValueChanged(Property); TargetObject.NotifyAnimatedValueChanged(Property);
} }
} }

11
src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs

@ -1,12 +1,11 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
// ReSharper disable CheckNamespace // ReSharper disable CheckNamespace
using System;
using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
using Avalonia.Rendering.Composition.Transport;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
@ -14,10 +13,10 @@ namespace Avalonia.Rendering.Composition.Animations
/// This is the base class for ExpressionAnimation and KeyFrameAnimation. /// This is the base class for ExpressionAnimation and KeyFrameAnimation.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Use the <see cref="CompositionObject.StartAnimation"/> method to start the animation. /// Use the <see cref="CompositionObject.StartAnimation(string , CompositionAnimation)"/> method to start the animation.
/// Value parameters (as opposed to reference parameters which are set using <see cref="SetReferenceParameter"/>) /// Value parameters (as opposed to reference parameters which are set using <see cref="SetReferenceParameter"/>)
/// are copied and "embedded" into an expression at the time CompositionObject.StartAnimation is called. /// are copied and "embedded" into an expression at the time CompositionObject.StartAnimation is called.
/// Changing the value of the variable after <see cref="CompositionObject.StartAnimation"/> is called will not affect /// Changing the value of the variable after <see cref="CompositionObject.StartAnimation(string , CompositionAnimation)"/> is called will not affect
/// the value of the ExpressionAnimation. /// the value of the ExpressionAnimation.
/// See the remarks section of ExpressionAnimation for additional information. /// See the remarks section of ExpressionAnimation for additional information.
/// </remarks> /// </remarks>
@ -72,4 +71,4 @@ namespace Avalonia.Rendering.Composition.Animations
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs

@ -3,6 +3,8 @@ using System.Collections.Generic;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
public class CompositionAnimationGroup : CompositionObject, ICompositionAnimationBase public class CompositionAnimationGroup : CompositionObject, ICompositionAnimationBase
@ -21,4 +23,4 @@ namespace Avalonia.Rendering.Composition.Animations
{ {
} }
} }
} }

6
src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs

@ -3,6 +3,8 @@ using System;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
/// <summary> /// <summary>
@ -14,7 +16,7 @@ namespace Avalonia.Rendering.Composition.Animations
/// This contrasts <see cref="KeyFrameAnimation"/>s, which use an interpolator to define how the animating /// This contrasts <see cref="KeyFrameAnimation"/>s, which use an interpolator to define how the animating
/// property changes over time. The mathematical equation can be defined using references to properties /// property changes over time. The mathematical equation can be defined using references to properties
/// of Composition objects, mathematical functions and operators and Input. /// of Composition objects, mathematical functions and operators and Input.
/// Use the <see cref="CompositionObject.StartAnimation"/> method to start the animation. /// Use the <see cref="CompositionObject.StartAnimation(string , CompositionAnimation)"/> method to start the animation.
/// </remarks> /// </remarks>
public class ExpressionAnimation : CompositionAnimation public class ExpressionAnimation : CompositionAnimation
{ {
@ -50,4 +52,4 @@ namespace Avalonia.Rendering.Composition.Animations
=> new ExpressionAnimationInstance(ParsedExpression, => new ExpressionAnimationInstance(ParsedExpression,
targetObject, finalValue, CreateSnapshot()); targetObject, finalValue, CreateSnapshot());
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs

@ -3,6 +3,8 @@ using System.Collections.Generic;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
@ -46,4 +48,4 @@ namespace Avalonia.Rendering.Composition.Animations
_finalValue = finalValue; _finalValue = finalValue;
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs

@ -2,6 +2,8 @@ using System;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
internal interface IAnimationInstance internal interface IAnimationInstance
@ -13,4 +15,4 @@ namespace Avalonia.Rendering.Composition.Animations
void Deactivate(); void Deactivate();
void Invalidate(); void Invalidate();
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs

@ -2,6 +2,8 @@
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
/// <summary> /// <summary>
@ -12,4 +14,4 @@ namespace Avalonia.Rendering.Composition.Animations
internal void InternalOnly(); internal void InternalOnly();
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs

@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
/// <summary> /// <summary>
@ -79,4 +81,4 @@ namespace Avalonia.Rendering.Composition.Animations
return rv; return rv;
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs

@ -1,6 +1,8 @@
using System; using System;
using System.Numerics; using System.Numerics;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
/// <summary> /// <summary>
@ -73,4 +75,4 @@ namespace Avalonia.Rendering.Composition.Animations
public static BooleanInterpolator Instance { get; } = new BooleanInterpolator(); public static BooleanInterpolator Instance { get; } = new BooleanInterpolator();
} }
} }

8
src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs

@ -2,6 +2,8 @@ using System;
using Avalonia.Animation; using Avalonia.Animation;
using Avalonia.Animation.Easings; using Avalonia.Animation.Easings;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
@ -22,9 +24,9 @@ namespace Avalonia.Rendering.Composition.Animations
/// The delay behavior of the key frame animation. /// The delay behavior of the key frame animation.
/// </summary> /// </summary>
public AnimationDelayBehavior DelayBehavior { get; set; } public AnimationDelayBehavior DelayBehavior { get; set; }
/// <summary> /// <summary>
/// Delay before the animation starts after <see cref="CompositionObject.StartAnimation"/> is called. /// Delay before the animation starts after <see cref="CompositionObject.StartAnimation(string , CompositionAnimation)"/> is called.
/// </summary> /// </summary>
public System.TimeSpan DelayTime { get; set; } public System.TimeSpan DelayTime { get; set; }
@ -131,4 +133,4 @@ namespace Avalonia.Rendering.Composition.Animations
/// </summary> /// </summary>
SetToFinalValue SetToFinalValue
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs

@ -4,6 +4,8 @@ using Avalonia.Animation;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
/// <summary> /// <summary>
@ -175,4 +177,4 @@ namespace Avalonia.Rendering.Composition.Animations
base.Deactivate(); base.Deactivate();
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs

@ -3,6 +3,8 @@ using System.Collections.Generic;
using Avalonia.Animation.Easings; using Avalonia.Animation.Easings;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
@ -86,4 +88,4 @@ namespace Avalonia.Rendering.Composition.Animations
{ {
public void InsertExpressionKeyFrame(float normalizedProgressKey, string value, IEasing easingFunction); public void InsertExpressionKeyFrame(float normalizedProgressKey, string value, IEasing easingFunction);
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs

@ -1,6 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Animations namespace Avalonia.Rendering.Composition.Animations
{ {
/// <summary> /// <summary>
@ -46,4 +48,4 @@ namespace Avalonia.Rendering.Composition.Animations
public ExpressionVariant GetProperty(string name) => GetParameter(name); public ExpressionVariant GetProperty(string name) => GetParameter(name);
} }
} }

2
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -11,6 +11,8 @@ using Avalonia.Rendering.Composition.Server;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.VisualTree; using Avalonia.VisualTree;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition; namespace Avalonia.Rendering.Composition;
/// <summary> /// <summary>

4
src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs

@ -5,6 +5,8 @@ using Avalonia.Rendering.Composition.Server;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
using Avalonia.VisualTree; using Avalonia.VisualTree;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition; namespace Avalonia.Rendering.Composition;
@ -72,4 +74,4 @@ internal class CompositionDrawListVisual : CompositionContainerVisual
return true; return true;
return false; return false;
} }
} }

4
src/Avalonia.Base/Rendering/Composition/CompositionObject.cs

@ -5,6 +5,8 @@ using Avalonia.Rendering.Composition.Server;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -138,4 +140,4 @@ namespace Avalonia.Rendering.Composition
writer.Write((byte)(IsDisposed ? 1 : 0)); writer.Write((byte)(IsDisposed ? 1 : 0));
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs

@ -5,6 +5,8 @@ using Avalonia.Rendering.Composition.Animations;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -144,4 +146,4 @@ namespace Avalonia.Rendering.Composition
TypeMismatch, TypeMismatch,
NotFound NotFound
} }
} }

4
src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs

@ -4,6 +4,8 @@ using System.Numerics;
using Avalonia.Collections.Pooled; using Avalonia.Collections.Pooled;
using Avalonia.VisualTree; using Avalonia.VisualTree;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -127,4 +129,4 @@ namespace Avalonia.Rendering.Composition
Compositor.Server.Render(); Compositor.Server.Render();
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Compositor.cs

@ -12,6 +12,8 @@ using Avalonia.Rendering.Composition.Transport;
using Avalonia.Threading; using Avalonia.Threading;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -138,4 +140,4 @@ namespace Avalonia.Rendering.Composition
_invokeOnNextCommit.Add(action); _invokeOnNextCommit.Add(action);
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs

@ -1,5 +1,7 @@
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -21,4 +23,4 @@ namespace Avalonia.Rendering.Composition
base.OnRootChangedCore(); base.OnRootChangedCore();
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs

@ -4,6 +4,8 @@ using Avalonia.Rendering.Composition.Server;
using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Drawing; namespace Avalonia.Rendering.Composition.Drawing;
/// <summary> /// <summary>
@ -99,4 +101,4 @@ internal class CompositionDrawListBuilder
if (count < Count) if (count < Count)
_operations!.RemoveRange(count, _operations.Count - count); _operations!.RemoveRange(count, _operations.Count - count);
} }
} }

5
src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs

@ -8,6 +8,9 @@ using Avalonia.Rendering.Composition.Drawing;
using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.VisualTree; using Avalonia.VisualTree;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition; namespace Avalonia.Rendering.Composition;
/// <summary> /// <summary>
@ -388,4 +391,4 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW
} }
return null; return null;
} }
} }

4
src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs

@ -1,3 +1,5 @@
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition; namespace Avalonia.Rendering.Composition;
/// <summary> /// <summary>
@ -11,4 +13,4 @@ public static class ElementComposition
/// <param name="visual"></param> /// <param name="visual"></param>
/// <returns></returns> /// <returns></returns>
public static CompositionVisual? GetElementVisual(Visual visual) => visual.CompositionVisual; public static CompositionVisual? GetElementVisual(Visual visual) => visual.CompositionVisual;
} }

4
src/Avalonia.Base/Rendering/Composition/Enums.cs

@ -1,5 +1,7 @@
using System; using System;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
public enum CompositionBlendMode public enum CompositionBlendMode
@ -117,4 +119,4 @@ namespace Avalonia.Rendering.Composition
Fill = 1, Fill = 1,
//TODO: Uniform, UniformToFill //TODO: Uniform, UniformToFill
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs

@ -4,6 +4,8 @@ using System.Numerics;
using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Animations;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
/// <summary> /// <summary>
@ -234,4 +236,4 @@ namespace Avalonia.Rendering.Composition.Expressions
public static BuiltInExpressionFfi Instance { get; } = new BuiltInExpressionFfi(); public static BuiltInExpressionFfi Instance { get; } = new BuiltInExpressionFfi();
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs

@ -5,6 +5,8 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using Avalonia.Media; using Avalonia.Media;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
/// <summary> /// <summary>
@ -181,4 +183,4 @@ namespace Avalonia.Rendering.Composition.Expressions
); );
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs

@ -4,6 +4,8 @@ using System.Globalization;
using System.Reflection; using System.Reflection;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
/// <summary> /// <summary>
@ -374,4 +376,4 @@ namespace Avalonia.Rendering.Composition.Expressions
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs

@ -1,6 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
internal struct ExpressionEvaluationContext internal struct ExpressionEvaluationContext
@ -29,4 +31,4 @@ namespace Avalonia.Rendering.Composition.Expressions
{ {
bool Call(string name, IReadOnlyList<ExpressionVariant> arguments, out ExpressionVariant result); bool Call(string name, IReadOnlyList<ExpressionVariant> arguments, out ExpressionVariant result);
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParseException.cs

@ -1,5 +1,7 @@
using System; using System;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
internal class ExpressionParseException : Exception internal class ExpressionParseException : Exception
@ -11,4 +13,4 @@ namespace Avalonia.Rendering.Composition.Expressions
Position = position; Position = position;
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionParser.cs

@ -5,6 +5,8 @@ using System.Linq;
// ReSharper disable StringLiteralTypo // ReSharper disable StringLiteralTypo
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
internal class ExpressionParser internal class ExpressionParser
@ -295,4 +297,4 @@ namespace Avalonia.Rendering.Composition.Expressions
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionTrackedValues.cs

@ -2,6 +2,8 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions; namespace Avalonia.Rendering.Composition.Expressions;
internal class ExpressionTrackedObjects : IEnumerable<IExpressionObject> internal class ExpressionTrackedObjects : IEnumerable<IExpressionObject>
@ -54,4 +56,4 @@ internal class ExpressionTrackedObjects : IEnumerable<IExpressionObject>
_stack.Push(obj); _stack.Push(obj);
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs

@ -4,6 +4,8 @@ using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Media; using Avalonia.Media;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
internal enum VariantType internal enum VariantType
@ -727,4 +729,4 @@ namespace Avalonia.Rendering.Composition.Expressions
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs

@ -1,6 +1,8 @@
using System; using System;
using System.Globalization; using System.Globalization;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Expressions namespace Avalonia.Rendering.Composition.Expressions
{ {
/// <summary> /// <summary>
@ -256,4 +258,4 @@ namespace Avalonia.Rendering.Composition.Expressions
public override string ToString() => _s.ToString(); public override string ToString() => _s.ToString();
} }
} }

4
src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs

@ -1,6 +1,8 @@
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition; namespace Avalonia.Rendering.Composition;
internal interface ICompositionTargetDebugEvents internal interface ICompositionTargetDebugEvents
{ {
void RectInvalidated(Rect rc); void RectInvalidated(Rect rc);
} }

7
src/Avalonia.Base/Rendering/Composition/License.md

@ -0,0 +1,7 @@
Please note: Any code in this directory is excluded from the normal MIT license.
This code is owned and copyright to Avalonia OU.
This code may be used free of charge by any application that consumes Avalonia binary packages as a direct or indirect dependency.
Explicit permission is required for any other use outside of Avalonia applications.

4
src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs

@ -1,5 +1,7 @@
using System.Numerics; using System.Numerics;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
static class MatrixUtils static class MatrixUtils
@ -63,4 +65,4 @@ namespace Avalonia.Rendering.Composition
matrix44.M42, matrix44.M42,
matrix44.M44); matrix44.M44);
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs

@ -1,6 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server; namespace Avalonia.Rendering.Composition.Server;
internal class CompositionProperty internal class CompositionProperty
@ -12,4 +14,4 @@ internal class CompositionProperty
{ {
Id = Interlocked.Increment(ref s_NextId) Id = Interlocked.Increment(ref s_NextId)
}; };
} }

4
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@ -6,6 +6,8 @@ using Avalonia.Rendering.Composition.Drawing;
using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server; namespace Avalonia.Rendering.Composition.Server;
/// <summary> /// <summary>
@ -176,4 +178,4 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl, IDrawingCont
if (_impl is IDrawingContextWithAcrylicLikeSupport acrylic) if (_impl is IDrawingContextWithAcrylicLikeSupport acrylic)
acrylic.DrawRectangle(material, rect); acrylic.DrawRectangle(material, rect);
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs

@ -6,6 +6,8 @@ using Avalonia.Media.TextFormatting;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server; namespace Avalonia.Rendering.Composition.Server;
/// <summary> /// <summary>
@ -73,4 +75,4 @@ internal class FpsCounter
offset += run.Size.Width; offset += run.Size.Width;
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs

@ -1,3 +1,5 @@
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -43,4 +45,4 @@ namespace Avalonia.Rendering.Composition.Server
} }
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs

@ -1,6 +1,8 @@
using System.Numerics; using System.Numerics;
using Avalonia.Platform; using Avalonia.Platform;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -41,4 +43,4 @@ namespace Avalonia.Rendering.Composition.Server
Children = new ServerCompositionVisualCollection(Compositor); Children = new ServerCompositionVisualCollection(Compositor);
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs

@ -7,6 +7,8 @@ using Avalonia.Rendering.Composition.Transport;
using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server; namespace Avalonia.Rendering.Composition.Server;
/// <summary> /// <summary>
@ -72,4 +74,4 @@ internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisua
return UiVisual.GetType().ToString(); return UiVisual.GetType().ToString();
} }
#endif #endif
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionSurface.cs

@ -1,3 +1,5 @@
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
internal abstract class ServerCompositionSurface : ServerObject internal abstract class ServerCompositionSurface : ServerObject
@ -6,4 +8,4 @@ namespace Avalonia.Rendering.Composition.Server
{ {
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@ -9,6 +9,8 @@ using Avalonia.Platform;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -218,4 +220,4 @@ namespace Avalonia.Rendering.Composition.Server
public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual); public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual);
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs

@ -1,3 +1,5 @@
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server; namespace Avalonia.Rendering.Composition.Server;
partial class ServerCompositionVisual partial class ServerCompositionVisual
@ -73,4 +75,4 @@ partial class ServerCompositionVisual
|| offset == s_IdOfSizeProperty) || offset == s_IdOfSizeProperty)
_clipSizeDirty = true; _clipSizeDirty = true;
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs

@ -6,6 +6,8 @@ using Avalonia.Rendering.Composition.Animations;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -234,4 +236,4 @@ namespace Avalonia.Rendering.Composition.Server
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs

@ -6,6 +6,8 @@ using Avalonia.Rendering.Composition.Animations;
using Avalonia.Rendering.Composition.Expressions; using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -137,4 +139,4 @@ namespace Avalonia.Rendering.Composition.Server
public void RemoveFromClock(IAnimationInstance animationInstance) => public void RemoveFromClock(IAnimationInstance animationInstance) =>
_activeAnimations.Remove(animationInstance); _activeAnimations.Remove(animationInstance);
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs

@ -2,6 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -41,4 +43,4 @@ namespace Avalonia.Rendering.Composition.Server
{ {
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs

@ -7,6 +7,8 @@ using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
using Avalonia.Utilities; using Avalonia.Utilities;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Server namespace Avalonia.Rendering.Composition.Server
{ {
/// <summary> /// <summary>
@ -177,4 +179,4 @@ namespace Avalonia.Rendering.Composition.Server
ItselfLastChangedBy = batch.SequenceId; ItselfLastChangedBy = batch.SequenceId;
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs

@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Transport namespace Avalonia.Rendering.Composition.Transport
{ {
/// <summary> /// <summary>
@ -36,4 +38,4 @@ namespace Avalonia.Rendering.Composition.Transport
public Task Completed => _tcs.Task; public Task Completed => _tcs.Task;
} }
} }

2
src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs

@ -5,6 +5,8 @@ using System.Runtime.CompilerServices;
using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Animations;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Transport; namespace Avalonia.Rendering.Composition.Transport;
/// <summary> /// <summary>

4
src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamArrayPool.cs

@ -5,6 +5,8 @@ using System.Runtime.InteropServices;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Transport; namespace Avalonia.Rendering.Composition.Transport;
/// <summary> /// <summary>
@ -153,4 +155,4 @@ internal sealed class BatchStreamMemoryPool : BatchStreamPoolBase<IntPtr>
protected override IntPtr CreateItem() => Marshal.AllocHGlobal(BufferSize); protected override IntPtr CreateItem() => Marshal.AllocHGlobal(BufferSize);
protected override void DestroyItem(IntPtr item) => Marshal.FreeHGlobal(item); protected override void DestroyItem(IntPtr item) => Marshal.FreeHGlobal(item);
} }

4
src/Avalonia.Base/Rendering/Composition/Transport/BatchStreamDebugMarker.cs

@ -1,9 +1,11 @@
using System; using System;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Transport; namespace Avalonia.Rendering.Composition.Transport;
internal class BatchStreamDebugMarkers internal class BatchStreamDebugMarkers
{ {
public static object ObjectEndMarker = new object(); public static object ObjectEndMarker = new object();
public static Guid ObjectEndMagic = Guid.NewGuid(); public static Guid ObjectEndMagic = Guid.NewGuid();
} }

4
src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs

@ -2,6 +2,8 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition.Transport namespace Avalonia.Rendering.Composition.Transport
{ {
/// <summary> /// <summary>
@ -95,4 +97,4 @@ namespace Avalonia.Rendering.Composition.Transport
_changed = false; _changed = false;
} }
} }
} }

4
src/Avalonia.Base/Rendering/Composition/Visual.cs

@ -3,6 +3,8 @@ using System.Numerics;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.VisualTree; using Avalonia.VisualTree;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -53,4 +55,4 @@ namespace Avalonia.Rendering.Composition
internal virtual bool HitTest(Point point, Func<IVisual, bool>? filter) => true; internal virtual bool HitTest(Point point, Func<IVisual, bool>? filter) => true;
} }
} }

4
src/Avalonia.Base/Rendering/Composition/VisualCollection.cs

@ -1,6 +1,8 @@
using System; using System;
using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Server;
// Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
namespace Avalonia.Rendering.Composition namespace Avalonia.Rendering.Composition
{ {
/// <summary> /// <summary>
@ -70,4 +72,4 @@ namespace Avalonia.Rendering.Composition
item.Parent = item; item.Parent = item;
} }
} }
} }

3
src/Avalonia.Base/Rendering/Composition/readme.md

@ -0,0 +1,3 @@
Please note the composition renderer is not subject to the usual MIT license.
Please contact us for more details and see [License.md](https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md)

2
src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs

@ -83,7 +83,7 @@ namespace Avalonia.Rendering.SceneGraph
if (Material != null) if (Material != null)
{ {
var rect = Rect.Rect; var rect = Rect.Rect;
return rect.Contains(p); return rect.ContainsExclusive(p);
} }
} }

4
src/Avalonia.Base/Rendering/SceneGraph/GeometryNode.cs

@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Immutable; using Avalonia.Media.Immutable;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
@ -19,7 +17,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="brush">The fill brush.</param> /// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param> /// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param> /// <param name="geometry">The geometry.</param>
/// <param name="childScenes">Child scenes for drawing visual brushes.</param> /// <param name="aux">Auxiliary data required to draw the brush.</param>
public GeometryNode(Matrix transform, public GeometryNode(Matrix transform,
IBrush? brush, IBrush? brush,
IPen? pen, IPen? pen,

8
src/Avalonia.Base/Rendering/SceneGraph/GlyphRunNode.cs

@ -1,10 +1,6 @@
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
@ -19,7 +15,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="transform">The transform.</param> /// <param name="transform">The transform.</param>
/// <param name="foreground">The foreground brush.</param> /// <param name="foreground">The foreground brush.</param>
/// <param name="glyphRun">The glyph run to draw.</param> /// <param name="glyphRun">The glyph run to draw.</param>
/// <param name="childScenes">Child scenes for drawing visual brushes.</param> /// <param name="aux">Auxiliary data required to draw the brush.</param>
public GlyphRunNode( public GlyphRunNode(
Matrix transform, Matrix transform,
IBrush foreground, IBrush foreground,
@ -73,6 +69,6 @@ namespace Avalonia.Rendering.SceneGraph
} }
/// <inheritdoc/> /// <inheritdoc/>
public override bool HitTest(Point p) => Bounds.Contains(p); public override bool HitTest(Point p) => Bounds.ContainsExclusive(p);
} }
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save