Browse Source

Merge branch 'master' into feature/window-integration-tests

pull/8232/head
Steven Kirk 4 years ago
committed by GitHub
parent
commit
4a12fbcc75
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .editorconfig
  2. 1490
      Avalonia.sln
  3. 1
      build/CoreLibraries.props
  4. 7
      native/Avalonia.Native/src/OSX/AvnView.mm
  5. 8
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  6. 1
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  7. 58
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  8. 5
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  9. 11
      native/Avalonia.Native/src/OSX/app.mm
  10. 1
      nukebuild/Build.cs
  11. 30
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  12. 3
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  13. 1
      samples/ControlCatalog.Android/environment.device.txt
  14. 1
      samples/ControlCatalog.Android/environment.emulator.txt
  15. 10
      samples/ControlCatalog/Converter/MathSubtractConverter.cs
  16. 10
      samples/ControlCatalog/DecoratedWindow.xaml.cs
  17. 16
      samples/ControlCatalog/MainView.xaml.cs
  18. 6
      samples/ControlCatalog/MainWindow.xaml.cs
  19. 4
      samples/ControlCatalog/Models/Countries.cs
  20. 4
      samples/ControlCatalog/Models/GDPValueConverter.cs
  21. 16
      samples/ControlCatalog/Models/Person.cs
  22. 33
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  23. 2
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
  24. 4
      samples/ControlCatalog/Pages/ButtonsPage.xaml.cs
  25. 12
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs
  26. 4
      samples/ControlCatalog/Pages/CalendarPage.xaml.cs
  27. 11
      samples/ControlCatalog/Pages/CarouselPage.xaml.cs
  28. 22
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs
  29. 6
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  30. 8
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  31. 4
      samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs
  32. 32
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  33. 6
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  34. 8
      samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs
  35. 13
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  36. 26
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  37. 2
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  38. 2
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  39. 2
      samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs
  40. 2
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  41. 10
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs
  42. 2
      samples/ControlCatalog/Pages/ScreenPage.cs
  43. 12
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  44. 2
      samples/ControlCatalog/Pages/TabStripPage.xaml.cs
  45. 2
      samples/ControlCatalog/ViewModels/ApplicationViewModel.cs
  46. 2
      samples/ControlCatalog/ViewModels/ContextPageViewModel.cs
  47. 2
      samples/ControlCatalog/ViewModels/CursorPageViewModel.cs
  48. 19
      samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
  49. 13
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  50. 8
      samples/ControlCatalog/ViewModels/MenuItemViewModel.cs
  51. 2
      samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
  52. 4
      samples/ControlCatalog/ViewModels/NotificationViewModel.cs
  53. 16
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  54. 4
      samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
  55. 4
      samples/RenderDemo/Pages/FormattedTextPage.axaml.cs
  56. 12
      samples/RenderDemo/Pages/GlyphRunPage.xaml
  57. 113
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  58. 2
      src/Android/Avalonia.Android/AndroidPlatform.cs
  59. 7
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  60. 2
      src/Android/Avalonia.Android/AvaloniaView.cs
  61. 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  62. BIN
      src/Avalonia.Base/Assets/BiDi.trie
  63. BIN
      src/Avalonia.Base/Assets/GraphemeBreak.trie
  64. BIN
      src/Avalonia.Base/Assets/UnicodeData.trie
  65. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  66. 37
      src/Avalonia.Base/GeometryCollection.cs
  67. 14
      src/Avalonia.Base/Layout/LayoutManager.cs
  68. 76
      src/Avalonia.Base/Matrix.cs
  69. 18
      src/Avalonia.Base/Media/DrawingCollection.cs
  70. 420
      src/Avalonia.Base/Media/DrawingGroup.cs
  71. 129
      src/Avalonia.Base/Media/FormattedText.cs
  72. 45
      src/Avalonia.Base/Media/GeometryCollection.cs
  73. 15
      src/Avalonia.Base/Media/GeometryDrawing.cs
  74. 58
      src/Avalonia.Base/Media/GeometryGroup.cs
  75. 13
      src/Avalonia.Base/Media/GlyphRun.cs
  76. 24
      src/Avalonia.Base/Media/PlatformGeometry.cs
  77. 42
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDi.trie.cs
  78. 31
      src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.trie.cs
  79. 39
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.cs
  80. 122
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.trie.cs
  81. 5
      src/Avalonia.Base/Platform/AssetLoader.cs
  82. 7
      src/Avalonia.Base/Platform/IPlatformRenderInterface.cs
  83. 2
      src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs
  84. 6
      src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs
  85. 2
      src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs
  86. 2
      src/Avalonia.Base/Platform/Internal/Constants.cs
  87. 58
      src/Avalonia.Base/Platform/Internal/DynLoader.cs
  88. 2
      src/Avalonia.Base/Platform/Internal/SlicedStream.cs
  89. 155
      src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs
  90. 5
      src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs
  91. 58
      src/Avalonia.Base/Platform/StandardRuntimePlatform.cs
  92. 15
      src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs
  93. 14
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  94. 1
      src/Avalonia.Base/PropertyStore/PriorityValue.cs
  95. 6
      src/Avalonia.Base/Reactive/TypedBindingAdapter.cs
  96. 27
      src/Avalonia.Base/Styling/PropertySetterInstance.cs
  97. 95
      src/Avalonia.Base/Styling/Styles.cs
  98. 2
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  99. 2
      src/Avalonia.Base/Threading/Dispatcher.cs
  100. 9
      src/Avalonia.Base/Threading/IDispatcher.cs

1
.editorconfig

@ -21,6 +21,7 @@ csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true csharp_new_line_between_query_expression_clauses = true
trim_trailing_whitespace = true
# Indentation preferences # Indentation preferences
csharp_indent_block_contents = true csharp_indent_block_contents = true

1490
Avalonia.sln

File diff suppressed because it is too large

1
build/CoreLibraries.props

@ -8,6 +8,5 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

7
native/Avalonia.Native/src/OSX/AvnView.mm

@ -439,7 +439,12 @@
if(_parent != nullptr) if(_parent != nullptr)
{ {
_lastKeyHandled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key); auto handled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key);
if (key != LeftCtrl && key != RightCtrl) {
_lastKeyHandled = handled;
} else {
_lastKeyHandled = false;
}
} }
} }

8
native/Avalonia.Native/src/OSX/AvnWindow.mm

@ -284,6 +284,14 @@
- (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification - (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification
{ {
_parent->BringToFront(); _parent->BringToFront();
dispatch_async(dispatch_get_main_queue(), ^{
@try {
[self invalidateShadow];
}
@finally{
}
});
} }
- (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification - (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification

1
native/Avalonia.Native/src/OSX/WindowBaseImpl.h

@ -110,7 +110,6 @@ protected:
private: private:
void CreateNSWindow (bool isDialog); void CreateNSWindow (bool isDialog);
void CleanNSWindow (); void CleanNSWindow ();
void InitialiseNSWindow ();
NSCursor *cursor; NSCursor *cursor;
ComPtr<IAvnGlContext> _glContext; ComPtr<IAvnGlContext> _glContext;

58
native/Avalonia.Native/src/OSX/WindowBaseImpl.mm

@ -39,7 +39,16 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl,
lastMenu = nullptr; lastMenu = nullptr;
CreateNSWindow(usePanel); CreateNSWindow(usePanel);
InitialiseNSWindow();
[Window setContentView:StandardContainer];
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];
[Window setContentMinSize:lastMinSize];
[Window setContentMaxSize:lastMaxSize];
[Window setOpaque:false];
[Window setHasShadow:true];
} }
HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) { HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) {
@ -90,6 +99,8 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) {
START_COM_CALL; START_COM_CALL;
@autoreleasepool { @autoreleasepool {
[Window setContentSize:lastSize];
if(hasPosition) if(hasPosition)
{ {
SetPosition(lastPositionSet); SetPosition(lastPositionSet);
@ -99,6 +110,8 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) {
} }
UpdateStyle(); UpdateStyle();
[Window invalidateShadow];
if (ShouldTakeFocusOnShow() && activate) { if (ShouldTakeFocusOnShow() && activate) {
[Window orderFront:Window]; [Window orderFront:Window];
@ -285,15 +298,15 @@ HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reaso
} }
@try { @try {
lastSize = NSSize {x, y}; if(x != lastSize.width || y != lastSize.height) {
lastSize = NSSize{x, y};
if (!_shown) {
BaseEvents->Resized(AvnSize{x, y}, reason); if (!_shown) {
} BaseEvents->Resized(AvnSize{x, y}, reason);
} else if (Window != nullptr) {
if(Window != nullptr) { [Window setContentSize:lastSize];
[Window setContentSize:lastSize]; [Window invalidateShadow];
[Window invalidateShadow]; }
} }
} }
@finally { @finally {
@ -567,31 +580,6 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) {
} }
} }
void WindowBaseImpl::InitialiseNSWindow() {
if(Window != nullptr) {
[Window setContentView:StandardContainer];
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];
[Window setContentSize:lastSize];
[Window setContentMinSize:lastMinSize];
[Window setContentMaxSize:lastMaxSize];
[Window setOpaque:false];
[Window setHasShadow:true];
[Window invalidateShadow];
if (lastMenu != nullptr) {
[GetWindowProtocol() applyMenu:lastMenu];
if ([Window isKeyWindow]) {
[GetWindowProtocol() showWindowMenuWithAppMenu];
}
}
}
}
id <AvnWindowProtocol> WindowBaseImpl::GetWindowProtocol() { id <AvnWindowProtocol> WindowBaseImpl::GetWindowProtocol() {
if(Window == nullptr) if(Window == nullptr)
{ {

5
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -55,11 +55,6 @@ void WindowImpl::OnInitialiseNSWindow(){
[GetWindowProtocol() setIsExtended:true]; [GetWindowProtocol() setIsExtended:true];
SetExtendClientArea(true); SetExtendClientArea(true);
} }
if(_parent != nullptr)
{
SetParent(_parent);
}
} }
HRESULT WindowImpl::Show(bool activate, bool isDialog) { HRESULT WindowImpl::Show(bool activate, bool isDialog) {

11
native/Avalonia.Native/src/OSX/app.mm

@ -82,6 +82,17 @@ ComPtr<IAvnApplicationEvents> _events;
_isHandlingSendEvent = oldHandling; _isHandlingSendEvent = oldHandling;
} }
} }
// This is needed for certain embedded controls DO NOT REMOVE..
- (BOOL) isHandlingSendEvent
{
return _isHandlingSendEvent;
}
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent
{
_isHandlingSendEvent = handlingSendEvent;
}
@end @end
extern void InitializeAvnApp(IAvnApplicationEvents* events) extern void InitializeAvnApp(IAvnApplicationEvents* events)

1
nukebuild/Build.cs

@ -221,7 +221,6 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.Markup.Xaml.UnitTests"); RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("Avalonia.Skia.UnitTests"); RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests"); RunCoreTest("Avalonia.ReactiveUI.UnitTests");
RunCoreTest("Avalonia.PlatformSupport.UnitTests");
}); });
Target RunRenderTests => _ => _ Target RunRenderTests => _ => _

30
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -9,39 +9,37 @@
<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>
<None Remove="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="..\..\build\Assets\Icon.png"> <AndroidResource Include="..\..\build\Assets\Icon.png">
<Link>Resources\drawable\Icon.png</Link> <Link>Resources\drawable\Icon.png</Link>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release' and '$(TF_BUILD)' == ''"> <PropertyGroup Condition="'$(RunAOTCompilation)'=='' and '$(Configuration)'=='Release' and '$(TF_BUILD)'==''">
<DebugSymbols>True</DebugSymbols>
<RunAOTCompilation>True</RunAOTCompilation> <RunAOTCompilation>True</RunAOTCompilation>
<EnableLLVM>True</EnableLLVM>
<AndroidEnableProfiledAot>True</AndroidEnableProfiledAot>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(RunAOTCompilation)'=='True'">
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk> <EnableLLVM>True</EnableLLVM>
<RunAOTCompilation>False</RunAOTCompilation> <AndroidAotAdditionalArguments>no-write-symbols,nodebug</AndroidAotAdditionalArguments>
<AndroidAotMode>Hybrid</AndroidAotMode>
<AndroidGenerateJniMarshalMethods>True</AndroidGenerateJniMarshalMethods>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(AndroidEnableProfiler)'=='True'">
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk> <IsEmulator Condition="'$(IsEmulator)' == ''">True</IsEmulator>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.1.3" /> <AndroidEnvironment Condition="'$(IsEmulator)'=='True'" Include="environment.emulator.txt" />
<PackageReference Include="Xamarin.AndroidX.Lifecycle.ViewModel" Version="2.3.1.3" /> <AndroidEnvironment Condition="'$(IsEmulator)'!='True'" Include="environment.device.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" /> <ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

3
samples/ControlCatalog.Android/Properties/AndroidManifest.xml

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> <application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest> </manifest>

1
samples/ControlCatalog.Android/environment.device.txt

@ -0,0 +1 @@
DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend

1
samples/ControlCatalog.Android/environment.emulator.txt

@ -0,0 +1 @@
DOTNET_DiagnosticPorts=10.0.2.2:9001,suspend

10
samples/ControlCatalog/Converter/MathSubtractConverter.cs

@ -6,12 +6,16 @@ namespace ControlCatalog.Converter;
public class MathSubtractConverter : IValueConverter public class MathSubtractConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
return (double)value - (double)parameter; if (value is double dv && parameter is double dp)
{
return dv - dp;
}
return double.NaN;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

10
samples/ControlCatalog/DecoratedWindow.xaml.cs

@ -15,7 +15,7 @@ namespace ControlCatalog
void SetupSide(string name, StandardCursorType cursor, WindowEdge edge) void SetupSide(string name, StandardCursorType cursor, WindowEdge edge)
{ {
var ctl = this.FindControl<Control>(name); var ctl = this.Get<Control>(name);
ctl.Cursor = new Cursor(cursor); ctl.Cursor = new Cursor(cursor);
ctl.PointerPressed += (i, e) => ctl.PointerPressed += (i, e) =>
{ {
@ -26,7 +26,7 @@ namespace ControlCatalog
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
this.FindControl<Control>("TitleBar").PointerPressed += (i, e) => this.Get<Control>("TitleBar").PointerPressed += (i, e) =>
{ {
PlatformImpl?.BeginMoveDrag(e); PlatformImpl?.BeginMoveDrag(e);
}; };
@ -38,12 +38,12 @@ namespace ControlCatalog
SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast); SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast);
SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest); SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest);
SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast); SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast);
this.FindControl<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; }; this.Get<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; };
this.FindControl<Button>("MaximizeButton").Click += delegate this.Get<Button>("MaximizeButton").Click += delegate
{ {
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}; };
this.FindControl<Button>("CloseButton").Click += delegate this.Get<Button>("CloseButton").Click += delegate
{ {
Close(); Close();
}; };

16
samples/ControlCatalog/MainView.xaml.cs

@ -18,9 +18,9 @@ namespace ControlCatalog
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
var sideBar = this.FindControl<TabControl>("Sidebar"); var sideBar = this.Get<TabControl>("Sidebar");
if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsDesktop) if (AvaloniaLocator.Current?.GetService<IRuntimePlatform>()?.GetRuntimeInfo().IsDesktop == true)
{ {
IList tabItems = ((IList)sideBar.Items); IList tabItems = ((IList)sideBar.Items);
tabItems.Add(new TabItem() tabItems.Add(new TabItem()
@ -36,7 +36,7 @@ namespace ControlCatalog
} }
var themes = this.Find<ComboBox>("Themes"); var themes = this.Get<ComboBox>("Themes");
themes.SelectionChanged += (sender, e) => themes.SelectionChanged += (sender, e) =>
{ {
if (themes.SelectedItem is CatalogTheme theme) if (themes.SelectedItem is CatalogTheme theme)
@ -80,7 +80,7 @@ namespace ControlCatalog
} }
}; };
var flowDirections = this.Find<ComboBox>("FlowDirection"); var flowDirections = this.Get<ComboBox>("FlowDirection");
flowDirections.SelectionChanged += (sender, e) => flowDirections.SelectionChanged += (sender, e) =>
{ {
if (flowDirections.SelectedItem is FlowDirection flowDirection) if (flowDirections.SelectedItem is FlowDirection flowDirection)
@ -89,7 +89,7 @@ namespace ControlCatalog
} }
}; };
var decorations = this.Find<ComboBox>("Decorations"); var decorations = this.Get<ComboBox>("Decorations");
decorations.SelectionChanged += (sender, e) => decorations.SelectionChanged += (sender, e) =>
{ {
if (VisualRoot is Window window if (VisualRoot is Window window
@ -99,8 +99,8 @@ namespace ControlCatalog
} }
}; };
var transparencyLevels = this.Find<ComboBox>("TransparencyLevels"); var transparencyLevels = this.Get<ComboBox>("TransparencyLevels");
IDisposable backgroundSetter = null, paneBackgroundSetter = null; IDisposable? backgroundSetter = null, paneBackgroundSetter = null;
transparencyLevels.SelectionChanged += (sender, e) => transparencyLevels.SelectionChanged += (sender, e) =>
{ {
backgroundSetter?.Dispose(); backgroundSetter?.Dispose();
@ -118,7 +118,7 @@ namespace ControlCatalog
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
var decorations = this.Find<ComboBox>("Decorations"); var decorations = this.Get<ComboBox>("Decorations");
if (VisualRoot is Window window) if (VisualRoot is Window window)
decorations.SelectedIndex = (int)window.SystemDecorations; decorations.SelectedIndex = (int)window.SystemDecorations;
} }

6
samples/ControlCatalog/MainWindow.xaml.cs

@ -12,7 +12,7 @@ namespace ControlCatalog
public class MainWindow : Window public class MainWindow : Window
{ {
private WindowNotificationManager _notificationArea; private WindowNotificationManager _notificationArea;
private NativeMenu _recentMenu; private NativeMenu? _recentMenu;
public MainWindow() public MainWindow()
{ {
@ -28,7 +28,7 @@ namespace ControlCatalog
}; };
DataContext = new MainWindowViewModel(_notificationArea); DataContext = new MainWindowViewModel(_notificationArea);
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; _recentMenu = ((NativeMenu.GetMenu(this)?.Items[0] as NativeMenuItem)?.Menu?.Items[2] as NativeMenuItem)?.Menu;
} }
public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit"; public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit";
@ -39,7 +39,7 @@ namespace ControlCatalog
public void OnOpenClicked(object sender, EventArgs args) public void OnOpenClicked(object sender, EventArgs args)
{ {
_recentMenu.Items.Insert(0, new NativeMenuItem("Item " + (_recentMenu.Items.Count + 1))); _recentMenu?.Items.Insert(0, new NativeMenuItem("Item " + (_recentMenu.Items.Count + 1)));
} }
public void OnCloseClicked(object sender, EventArgs args) public void OnCloseClicked(object sender, EventArgs args)

4
samples/ControlCatalog/Models/Countries.cs

@ -237,7 +237,7 @@ namespace ControlCatalog.Models
yield return new Country("Zimbabwe", "SUB-SAHARAN AFRICA", 12236805, 390580, 31.3, 0, 0, 67.69, 1900, 90.7, 26.8, 28.01, 21.84); yield return new Country("Zimbabwe", "SUB-SAHARAN AFRICA", 12236805, 390580, 31.3, 0, 0, 67.69, 1900, 90.7, 26.8, 28.01, 21.84);
} }
static IReadOnlyList<Country> _all; static IReadOnlyList<Country>? _all;
public static IReadOnlyList<Country> All public static IReadOnlyList<Country> All
{ {
@ -253,4 +253,4 @@ namespace ControlCatalog.Models
} }
} }
} }

4
samples/ControlCatalog/Models/GDPValueConverter.cs

@ -14,7 +14,7 @@ namespace ControlCatalog.Models
{ {
public class GDPValueConverter : IValueConverter public class GDPValueConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
if (value is int gdp) if (value is int gdp)
{ {
@ -29,7 +29,7 @@ namespace ControlCatalog.Models
return value; return value;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

16
samples/ControlCatalog/Models/Person.cs

@ -13,8 +13,8 @@ namespace ControlCatalog.Models
{ {
public class Person : INotifyDataErrorInfo, INotifyPropertyChanged public class Person : INotifyDataErrorInfo, INotifyPropertyChanged
{ {
string _firstName; string _firstName = string.Empty;
string _lastName; string _lastName = string.Empty;
bool _isBanned; bool _isBanned;
private int _age; private int _age;
@ -76,7 +76,7 @@ namespace ControlCatalog.Models
Dictionary<string, List<string>> _errorLookup = new Dictionary<string, List<string>>(); Dictionary<string, List<string>> _errorLookup = new Dictionary<string, List<string>>();
void SetError(string propertyName, string error) void SetError(string propertyName, string? error)
{ {
if (string.IsNullOrEmpty(error)) if (string.IsNullOrEmpty(error))
{ {
@ -88,11 +88,11 @@ namespace ControlCatalog.Models
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList)) if (_errorLookup.TryGetValue(propertyName, out List<string> errorList))
{ {
errorList.Clear(); errorList.Clear();
errorList.Add(error); errorList.Add(error!);
} }
else else
{ {
var errors = new List<string> { error }; var errors = new List<string> { error! };
_errorLookup.Add(propertyName, errors); _errorLookup.Add(propertyName, errors);
} }
@ -102,8 +102,8 @@ namespace ControlCatalog.Models
public bool HasErrors => _errorLookup.Count > 0; public bool HasErrors => _errorLookup.Count > 0;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
void OnErrorsChanged(string propertyName) void OnErrorsChanged(string propertyName)
{ {
@ -114,7 +114,7 @@ namespace ControlCatalog.Models
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
public IEnumerable GetErrors(string propertyName) public IEnumerable? GetErrors(string propertyName)
{ {
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList)) if (_errorLookup.TryGetValue(propertyName, out List<string> errorList))
return errorList; return errorList;

33
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -126,13 +126,13 @@ namespace ControlCatalog.Pages
binding.Bindings.Add(new Binding("Name")); binding.Bindings.Add(new Binding("Name"));
binding.Bindings.Add(new Binding("Abbreviation")); binding.Bindings.Add(new Binding("Abbreviation"));
var multibindingBox = this.FindControl<AutoCompleteBox>("MultiBindingBox"); var multibindingBox = this.Get<AutoCompleteBox>("MultiBindingBox");
multibindingBox.ValueMemberBinding = binding; multibindingBox.ValueMemberBinding = binding;
var asyncBox = this.FindControl<AutoCompleteBox>("AsyncBox"); var asyncBox = this.Get<AutoCompleteBox>("AsyncBox");
asyncBox.AsyncPopulator = PopulateAsync; asyncBox.AsyncPopulator = PopulateAsync;
var customAutocompleteBox = this.FindControl<AutoCompleteBox>("CustomAutocompleteBox"); var customAutocompleteBox = this.Get<AutoCompleteBox>("CustomAutocompleteBox");
customAutocompleteBox.Items = Sentences.SelectMany(x => x); customAutocompleteBox.Items = Sentences.SelectMany(x => x);
customAutocompleteBox.TextFilter = LastWordContains; customAutocompleteBox.TextFilter = LastWordContains;
customAutocompleteBox.TextSelector = AppendWord; customAutocompleteBox.TextSelector = AppendWord;
@ -144,11 +144,12 @@ namespace ControlCatalog.Pages
.OfType<AutoCompleteBox>(); .OfType<AutoCompleteBox>();
} }
private bool StringContains(string str, string query) private bool StringContains(string str, string? query)
{ {
if (query == null) return false;
return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
} }
private async Task<IEnumerable<object>> PopulateAsync(string searchText, CancellationToken cancellationToken) private async Task<IEnumerable<object>> PopulateAsync(string? searchText, CancellationToken cancellationToken)
{ {
await Task.Delay(TimeSpan.FromSeconds(1.5), cancellationToken); await Task.Delay(TimeSpan.FromSeconds(1.5), cancellationToken);
@ -157,14 +158,14 @@ namespace ControlCatalog.Pages
.ToList(); .ToList();
} }
private bool LastWordContains(string searchText, string item) private bool LastWordContains(string? searchText, string? item)
{ {
var words = searchText.Split(' '); var words = searchText?.Split(' ') ?? Array.Empty<string>();
var options = Sentences.Select(x => x.First).ToArray(); var options = Sentences.Select(x => x.First).ToArray();
for (var i = 0; i < words.Length; ++i) for (var i = 0; i < words.Length; ++i)
{ {
var word = words[i]; var word = words[i];
for (var j = 0; j < options.Length; ++j) for (var j = 0; word is { } && j < options.Length; ++j)
{ {
var option = options[j]; var option = options[j];
if (option == null) if (option == null)
@ -183,14 +184,18 @@ namespace ControlCatalog.Pages
return options.Any(x => x != null && x.Value == item); return options.Any(x => x != null && x.Value == item);
} }
private string AppendWord(string text, string item) private string AppendWord(string? text, string? item)
{ {
string[] parts = text.Split(' '); if (item is { })
if (parts.Length == 0) {
return item; string[] parts = text?.Split(' ') ?? Array.Empty<string>();
if (parts.Length == 0)
return item;
parts[parts.Length - 1] = item; parts[parts.Length - 1] = item;
return string.Join(" ", parts); return string.Join(" ", parts);
}
return string.Empty;
} }
private void InitializeComponent() private void InitializeComponent()

2
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs

@ -23,7 +23,7 @@ namespace ControlCatalog.Pages
var spinner = (ButtonSpinner)sender; var spinner = (ButtonSpinner)sender;
var txtBox = (TextBlock)spinner.Content; var txtBox = (TextBlock)spinner.Content;
int value = Array.IndexOf(_mountains, txtBox.Text); int value = Array.IndexOf(_mountains, txtBox?.Text);
if (e.Direction == SpinDirection.Increase) if (e.Direction == SpinDirection.Increase)
value++; value++;
else else

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

@ -11,7 +11,7 @@ namespace ControlCatalog.Pages
{ {
InitializeComponent(); InitializeComponent();
this.FindControl<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick; this.Get<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick;
} }
private void InitializeComponent() private void InitializeComponent()
@ -22,7 +22,7 @@ namespace ControlCatalog.Pages
public void OnRepeatButtonClick(object sender, object args) public void OnRepeatButtonClick(object sender, object args)
{ {
repeatButtonClickCount++; repeatButtonClickCount++;
var textBlock = this.FindControl<TextBlock>("RepeatButtonTextBlock"); var textBlock = this.Get<TextBlock>("RepeatButtonTextBlock");
textBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; textBlock.Text = $"Repeat Button: {repeatButtonClickCount}";
} }
} }

12
samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs

@ -10,11 +10,11 @@ namespace ControlCatalog.Pages
{ {
InitializeComponent(); InitializeComponent();
var dp1 = this.FindControl<CalendarDatePicker>("DatePicker1"); var dp1 = this.Get<CalendarDatePicker>("DatePicker1");
var dp2 = this.FindControl<CalendarDatePicker>("DatePicker2"); var dp2 = this.Get<CalendarDatePicker>("DatePicker2");
var dp3 = this.FindControl<CalendarDatePicker>("DatePicker3"); var dp3 = this.Get<CalendarDatePicker>("DatePicker3");
var dp4 = this.FindControl<CalendarDatePicker>("DatePicker4"); var dp4 = this.Get<CalendarDatePicker>("DatePicker4");
var dp5 = this.FindControl<CalendarDatePicker>("DatePicker5"); var dp5 = this.Get<CalendarDatePicker>("DatePicker5");
dp1.SelectedDate = DateTime.Today; dp1.SelectedDate = DateTime.Today;
dp2.SelectedDate = DateTime.Today.AddDays(10); dp2.SelectedDate = DateTime.Today.AddDays(10);
@ -23,7 +23,7 @@ namespace ControlCatalog.Pages
dp4.TemplateApplied += (s, e) => dp4.TemplateApplied += (s, e) =>
{ {
dp4.BlackoutDates.AddDatesInPast(); dp4.BlackoutDates?.AddDatesInPast();
}; };
} }

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

@ -11,11 +11,11 @@ namespace ControlCatalog.Pages
this.InitializeComponent(); this.InitializeComponent();
var today = DateTime.Today; var today = DateTime.Today;
var cal1 = this.FindControl<Calendar>("DisplayDatesCalendar"); var cal1 = this.Get<Calendar>("DisplayDatesCalendar");
cal1.DisplayDateStart = today.AddDays(-25); cal1.DisplayDateStart = today.AddDays(-25);
cal1.DisplayDateEnd = today.AddDays(25); cal1.DisplayDateEnd = today.AddDays(25);
var cal2 = this.FindControl<Calendar>("BlackoutDatesCalendar"); var cal2 = this.Get<Calendar>("BlackoutDatesCalendar");
cal2.BlackoutDates.AddDatesInPast(); cal2.BlackoutDates.AddDatesInPast();
cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6)));
} }

11
samples/ControlCatalog/Pages/CarouselPage.xaml.cs

@ -16,6 +16,11 @@ namespace ControlCatalog.Pages
public CarouselPage() public CarouselPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
_carousel = this.Get<Carousel>("carousel");
_left = this.Get<Button>("left");
_right = this.Get<Button>("right");
_transition = this.Get<ComboBox>("transition");
_orientation = this.Get<ComboBox>("orientation");
_left.Click += (s, e) => _carousel.Previous(); _left.Click += (s, e) => _carousel.Previous();
_right.Click += (s, e) => _carousel.Next(); _right.Click += (s, e) => _carousel.Next();
_transition.SelectionChanged += TransitionChanged; _transition.SelectionChanged += TransitionChanged;
@ -25,11 +30,7 @@ namespace ControlCatalog.Pages
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
_carousel = this.FindControl<Carousel>("carousel");
_left = this.FindControl<Button>("left");
_right = this.FindControl<Button>("right");
_transition = this.FindControl<ComboBox>("transition");
_orientation = this.FindControl<ComboBox>("orientation");
} }
private void TransitionChanged(object sender, SelectionChangedEventArgs e) private void TransitionChanged(object sender, SelectionChangedEventArgs e)

22
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs

@ -18,29 +18,29 @@ namespace ControlCatalog.Pages
DataContext = new ContextPageViewModel(); DataContext = new ContextPageViewModel();
_textBox = this.FindControl<TextBox>("TextBox"); _textBox = this.Get<TextBox>("TextBox");
var cutButton = this.FindControl<Button>("CutButton"); var cutButton = this.Get<Button>("CutButton");
cutButton.Click += CloseFlyout; cutButton.Click += CloseFlyout;
var copyButton = this.FindControl<Button>("CopyButton"); var copyButton = this.Get<Button>("CopyButton");
copyButton.Click += CloseFlyout; copyButton.Click += CloseFlyout;
var pasteButton = this.FindControl<Button>("PasteButton"); var pasteButton = this.Get<Button>("PasteButton");
pasteButton.Click += CloseFlyout; pasteButton.Click += CloseFlyout;
var clearButton = this.FindControl<Button>("ClearButton"); var clearButton = this.Get<Button>("ClearButton");
clearButton.Click += CloseFlyout; clearButton.Click += CloseFlyout;
var customContextRequestedBorder = this.FindControl<Border>("CustomContextRequestedBorder"); var customContextRequestedBorder = this.Get<Border>("CustomContextRequestedBorder");
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel); customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.FindControl<Border>("CancellableContextBorder"); var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextFlyout!.Closing += ContextFlyoutPage_Closing; cancellableContextBorder.ContextFlyout!.Closing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextFlyout!.Opening += ContextFlyoutPage_Opening; cancellableContextBorder.ContextFlyout!.Opening += ContextFlyoutPage_Opening;
} }
private ContextPageViewModel _model; private ContextPageViewModel? _model;
protected override void OnDataContextChanged(EventArgs e) protected override void OnDataContextChanged(EventArgs e)
{ {
if (_model != null) if (_model != null)
@ -55,7 +55,7 @@ namespace ControlCatalog.Pages
private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e) private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e)
{ {
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox"); var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox");
e.Cancel = cancelCloseCheckBox.IsChecked ?? false; e.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
} }
private void ContextFlyoutPage_Opening(object sender, EventArgs e) private void ContextFlyoutPage_Opening(object sender, EventArgs e)
@ -63,13 +63,13 @@ namespace ControlCatalog.Pages
if (e is CancelEventArgs cancelArgs) if (e is CancelEventArgs cancelArgs)
{ {
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox"); var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox");
cancelArgs.Cancel = cancelCloseCheckBox.IsChecked ?? false; cancelArgs.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
} }
} }
private void CloseFlyout(object sender, RoutedEventArgs e) private void CloseFlyout(object sender, RoutedEventArgs e)
{ {
_textBox.ContextFlyout.Hide(); _textBox.ContextFlyout?.Hide();
} }
public void CustomContextRequested(object sender, ContextRequestedEventArgs e) public void CustomContextRequested(object sender, ContextRequestedEventArgs e)

6
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@ -15,15 +15,15 @@ namespace ControlCatalog.Pages
this.InitializeComponent(); this.InitializeComponent();
DataContext = new ContextPageViewModel(); DataContext = new ContextPageViewModel();
var customContextRequestedBorder = this.FindControl<Border>("CustomContextRequestedBorder"); var customContextRequestedBorder = this.Get<Border>("CustomContextRequestedBorder");
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel); customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.FindControl<Border>("CancellableContextBorder"); var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing; cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening; cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening;
} }
private ContextPageViewModel _model; private ContextPageViewModel? _model;
protected override void OnDataContextChanged(EventArgs e) protected override void OnDataContextChanged(EventArgs e)
{ {
if (_model != null) if (_model != null)

8
samples/ControlCatalog/Pages/DataGridPage.xaml.cs

@ -21,7 +21,7 @@ namespace ControlCatalog.Pages
var dataGridSortDescription = DataGridSortDescription.FromPath(nameof(Country.Region), ListSortDirection.Ascending, new ReversedStringComparer()); var dataGridSortDescription = DataGridSortDescription.FromPath(nameof(Country.Region), ListSortDirection.Ascending, new ReversedStringComparer());
var collectionView1 = new DataGridCollectionView(Countries.All); var collectionView1 = new DataGridCollectionView(Countries.All);
collectionView1.SortDescriptions.Add(dataGridSortDescription); collectionView1.SortDescriptions.Add(dataGridSortDescription);
var dg1 = this.FindControl<DataGrid>("dataGrid1"); var dg1 = this.Get<DataGrid>("dataGrid1");
dg1.IsReadOnly = true; dg1.IsReadOnly = true;
dg1.LoadingRow += Dg1_LoadingRow; dg1.LoadingRow += Dg1_LoadingRow;
dg1.Sorting += (s, a) => dg1.Sorting += (s, a) =>
@ -37,7 +37,7 @@ namespace ControlCatalog.Pages
}; };
dg1.Items = collectionView1; dg1.Items = collectionView1;
var dg2 = this.FindControl<DataGrid>("dataGridGrouping"); var dg2 = this.Get<DataGrid>("dataGridGrouping");
dg2.IsReadOnly = true; dg2.IsReadOnly = true;
var collectionView2 = new DataGridCollectionView(Countries.All); var collectionView2 = new DataGridCollectionView(Countries.All);
@ -45,7 +45,7 @@ namespace ControlCatalog.Pages
dg2.Items = collectionView2; dg2.Items = collectionView2;
var dg3 = this.FindControl<DataGrid>("dataGridEdit"); var dg3 = this.Get<DataGrid>("dataGridEdit");
dg3.IsReadOnly = false; dg3.IsReadOnly = false;
var items = new List<Person> var items = new List<Person>
@ -58,7 +58,7 @@ namespace ControlCatalog.Pages
dg3.Items = collectionView3; dg3.Items = collectionView3;
var addButton = this.FindControl<Button>("btnAdd"); var addButton = this.Get<Button>("btnAdd");
addButton.Click += (a, b) => collectionView3.AddNew(); addButton.Click += (a, b) => collectionView3.AddNew();
} }

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

@ -9,12 +9,12 @@ namespace ControlCatalog.Pages
public DateTimePickerPage() public DateTimePickerPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
this.FindControl<TextBlock>("DatePickerDesc").Text = "Use a DatePicker to let users set a date in your app, " + this.Get<TextBlock>("DatePickerDesc").Text = "Use a DatePicker to let users set a date in your app, " +
"for example to schedule an appointment. The DatePicker displays three controls for month, day, and year. " + "for example to schedule an appointment. The DatePicker displays three controls for month, day, and year. " +
"These controls are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + "These controls are easy to use with touch or mouse, and they can be styled and configured in several different ways. " +
"Order of month, day, and year is dynamically set based on user date settings"; "Order of month, day, and year is dynamically set based on user date settings";
this.FindControl<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " + this.Get<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " +
"to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " + "to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " +
"are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + "are easy to use with touch or mouse, and they can be styled and configured in several different ways. " +
"12 - hour or 24 - hour clock and visiblility of AM / PM is dynamically set based on user time settings, or can be overridden."; "12 - hour or 24 - hour clock and visiblility of AM / PM is dynamically set based on user time settings, or can be overridden.";

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

@ -16,14 +16,14 @@ namespace ControlCatalog.Pages
{ {
this.InitializeComponent(); this.InitializeComponent();
var results = this.FindControl<ItemsPresenter>("PickerLastResults"); var results = this.Get<ItemsPresenter>("PickerLastResults");
var resultsVisible = this.FindControl<TextBlock>("PickerLastResultsVisible"); var resultsVisible = this.Get<TextBlock>("PickerLastResultsVisible");
string lastSelectedDirectory = null; string? lastSelectedDirectory = null;
List<FileDialogFilter>? GetFilters() List<FileDialogFilter>? GetFilters()
{ {
if (this.FindControl<CheckBox>("UseFilters").IsChecked != true) if (this.Get<CheckBox>("UseFilters").IsChecked != true)
return null; return null;
return new List<FileDialogFilter> return new List<FileDialogFilter>
{ {
@ -39,7 +39,7 @@ namespace ControlCatalog.Pages
}; };
} }
this.FindControl<Button>("OpenFile").Click += async delegate this.Get<Button>("OpenFile").Click += async delegate
{ {
// Almost guaranteed to exist // Almost guaranteed to exist
var fullPath = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName; var fullPath = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName;
@ -56,7 +56,7 @@ namespace ControlCatalog.Pages
results.Items = result; results.Items = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.FindControl<Button>("OpenMultipleFiles").Click += async delegate this.Get<Button>("OpenMultipleFiles").Click += async delegate
{ {
var result = await new OpenFileDialog() var result = await new OpenFileDialog()
{ {
@ -68,7 +68,7 @@ namespace ControlCatalog.Pages
results.Items = result; results.Items = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.FindControl<Button>("SaveFile").Click += async delegate this.Get<Button>("SaveFile").Click += async delegate
{ {
var result = await new SaveFileDialog() var result = await new SaveFileDialog()
{ {
@ -80,7 +80,7 @@ namespace ControlCatalog.Pages
results.Items = new[] { result }; results.Items = new[] { result };
resultsVisible.IsVisible = result != null; resultsVisible.IsVisible = result != null;
}; };
this.FindControl<Button>("SelectFolder").Click += async delegate this.Get<Button>("SelectFolder").Click += async delegate
{ {
var result = await new OpenFolderDialog() var result = await new OpenFolderDialog()
{ {
@ -96,7 +96,7 @@ namespace ControlCatalog.Pages
results.Items = new [] { result }; results.Items = new [] { result };
resultsVisible.IsVisible = result != null; resultsVisible.IsVisible = result != null;
}; };
this.FindControl<Button>("OpenBoth").Click += async delegate this.Get<Button>("OpenBoth").Click += async delegate
{ {
var result = await new OpenFileDialog() var result = await new OpenFileDialog()
{ {
@ -110,35 +110,35 @@ namespace ControlCatalog.Pages
results.Items = result; results.Items = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.FindControl<Button>("DecoratedWindow").Click += delegate this.Get<Button>("DecoratedWindow").Click += delegate
{ {
new DecoratedWindow().Show(); new DecoratedWindow().Show();
}; };
this.FindControl<Button>("DecoratedWindowDialog").Click += delegate this.Get<Button>("DecoratedWindowDialog").Click += delegate
{ {
new DecoratedWindow().ShowDialog(GetWindow()); new DecoratedWindow().ShowDialog(GetWindow());
}; };
this.FindControl<Button>("Dialog").Click += delegate this.Get<Button>("Dialog").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
window.Height = 200; window.Height = 200;
window.ShowDialog(GetWindow()); window.ShowDialog(GetWindow());
}; };
this.FindControl<Button>("DialogNoTaskbar").Click += delegate this.Get<Button>("DialogNoTaskbar").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
window.Height = 200; window.Height = 200;
window.ShowInTaskbar = false; window.ShowInTaskbar = false;
window.ShowDialog(GetWindow()); window.ShowDialog(GetWindow());
}; };
this.FindControl<Button>("OwnedWindow").Click += delegate this.Get<Button>("OwnedWindow").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
window.Show(GetWindow()); window.Show(GetWindow());
}; };
this.FindControl<Button>("OwnedWindowNoTaskbar").Click += delegate this.Get<Button>("OwnedWindowNoTaskbar").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
@ -191,7 +191,7 @@ namespace ControlCatalog.Pages
return window; return window;
} }
Window GetWindow() => (Window)this.VisualRoot; Window GetWindow() => this.VisualRoot as Window ?? throw new NullReferenceException("Invalid Owner");
private void InitializeComponent() private void InitializeComponent()
{ {

6
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@ -14,7 +14,7 @@ namespace ControlCatalog.Pages
public DragAndDropPage() public DragAndDropPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
_DropState = this.Find<TextBlock>("DropState"); _DropState = this.Get<TextBlock>("DropState");
int textCount = 0; int textCount = 0;
SetupDnd("Text", d => d.Set(DataFormats.Text, SetupDnd("Text", d => d.Set(DataFormats.Text,
@ -26,8 +26,8 @@ namespace ControlCatalog.Pages
void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects) void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
{ {
var dragMe = this.Find<Border>("DragMe" + suffix); var dragMe = this.Get<Border>("DragMe" + suffix);
var dragState = this.Find<TextBlock>("DragState"+suffix); var dragState = this.Get<TextBlock>("DragState"+suffix);
async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e) async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
{ {

8
samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs

@ -35,7 +35,7 @@ namespace ControlCatalog.Pages
private void SetXamlTexts() private void SetXamlTexts()
{ {
var bfxt = this.FindControl<TextBlock>("ButtonFlyoutXamlText"); var bfxt = this.Get<TextBlock>("ButtonFlyoutXamlText");
bfxt.Text = "<Button Content=\"Click me!\">\n" + bfxt.Text = "<Button Content=\"Click me!\">\n" +
" <Button.Flyout>\n" + " <Button.Flyout>\n" +
" <Flyout>\n" + " <Flyout>\n" +
@ -45,7 +45,7 @@ namespace ControlCatalog.Pages
" </Flyout>\n" + " </Flyout>\n" +
" </Button.Flyout>\n</Button>"; " </Button.Flyout>\n</Button>";
var mfxt = this.FindControl<TextBlock>("MenuFlyoutXamlText"); var mfxt = this.Get<TextBlock>("MenuFlyoutXamlText");
mfxt.Text = "<Button Content=\"Click me!\">\n" + mfxt.Text = "<Button Content=\"Click me!\">\n" +
" <Button.Flyout>\n" + " <Button.Flyout>\n" +
" <MenuFlyout>\n" + " <MenuFlyout>\n" +
@ -54,7 +54,7 @@ namespace ControlCatalog.Pages
" </MenuFlyout>\n" + " </MenuFlyout>\n" +
" </Button.Flyout>\n</Button>"; " </Button.Flyout>\n</Button>";
var afxt = this.FindControl<TextBlock>("AttachedFlyoutXamlText"); var afxt = this.Get<TextBlock>("AttachedFlyoutXamlText");
afxt.Text = "<Panel Name=\"AttachedFlyoutPanel\">\n" + afxt.Text = "<Panel Name=\"AttachedFlyoutPanel\">\n" +
" <FlyoutBase.AttachedFlyout>\n" + " <FlyoutBase.AttachedFlyout>\n" +
" <Flyout>\n" + " <Flyout>\n" +
@ -66,7 +66,7 @@ namespace ControlCatalog.Pages
"\n\n In DoubleTapped handler:\n" + "\n\n In DoubleTapped handler:\n" +
"FlyoutBase.ShowAttachedFlyout(AttachedFlyoutPanel);"; "FlyoutBase.ShowAttachedFlyout(AttachedFlyoutPanel);";
var sfxt = this.FindControl<TextBlock>("SharedFlyoutXamlText"); var sfxt = this.Get<TextBlock>("SharedFlyoutXamlText");
sfxt.Text = "Declare a flyout in Resources:\n" + sfxt.Text = "Declare a flyout in Resources:\n" +
"<Window.Resources>\n" + "<Window.Resources>\n" +
" <Flyout x:Key=\"SharedFlyout\">\n" + " <Flyout x:Key=\"SharedFlyout\">\n" +

13
samples/ControlCatalog/Pages/ImagePage.xaml.cs

@ -17,9 +17,9 @@ namespace ControlCatalog.Pages
public ImagePage() public ImagePage()
{ {
InitializeComponent(); InitializeComponent();
_bitmapImage = this.FindControl<Image>("bitmapImage"); _bitmapImage = this.Get<Image>("bitmapImage");
_drawingImage = this.FindControl<Image>("drawingImage"); _drawingImage = this.Get<Image>("drawingImage");
_croppedImage = this.FindControl<Image>("croppedImage"); _croppedImage = this.Get<Image>("croppedImage");
} }
private void InitializeComponent() private void InitializeComponent()
@ -50,8 +50,11 @@ namespace ControlCatalog.Pages
if (_croppedImage != null) if (_croppedImage != null)
{ {
var comboxBox = (ComboBox)sender; var comboxBox = (ComboBox)sender;
var croppedBitmap = _croppedImage.Source as CroppedBitmap; if (_croppedImage.Source is CroppedBitmap croppedBitmap)
croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex); {
croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex);
}
} }
} }

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

@ -24,11 +24,11 @@ namespace ControlCatalog.Pages
public ItemsRepeaterPage() public ItemsRepeaterPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
_repeater = this.FindControl<ItemsRepeater>("repeater"); _repeater = this.Get<ItemsRepeater>("repeater");
_scroller = this.FindControl<ScrollViewer>("scroller"); _scroller = this.Get<ScrollViewer>("scroller");
_scrollToLast = this.FindControl<Button>("scrollToLast"); _scrollToLast = this.Get<Button>("scrollToLast");
_scrollToRandom = this.FindControl<Button>("scrollToRandom"); _scrollToRandom = this.Get<Button>("scrollToRandom");
_scrollToSelected = this.FindControl<Button>("scrollToSelected"); _scrollToSelected = this.Get<Button>("scrollToSelected");
_repeater.PointerPressed += RepeaterClick; _repeater.PointerPressed += RepeaterClick;
_repeater.KeyDown += RepeaterOnKeyDown; _repeater.KeyDown += RepeaterOnKeyDown;
_scrollToLast.Click += scrollToLast_Click; _scrollToLast.Click += scrollToLast_Click;
@ -44,8 +44,10 @@ namespace ControlCatalog.Pages
public void OnSelectTemplateKey(object sender, SelectTemplateEventArgs e) public void OnSelectTemplateKey(object sender, SelectTemplateEventArgs e)
{ {
var item = (ItemsRepeaterPageViewModel.Item)e.DataContext; if (e.DataContext is ItemsRepeaterPageViewModel.Item item)
e.TemplateKey = (item.Index % 2 == 0) ? "even" : "odd"; {
e.TemplateKey = (item.Index % 2 == 0) ? "even" : "odd";
}
} }
private void LayoutChanged(object sender, SelectionChangedEventArgs e) private void LayoutChanged(object sender, SelectionChangedEventArgs e)
@ -115,7 +117,7 @@ namespace ControlCatalog.Pages
private void ScrollTo(int index) private void ScrollTo(int index)
{ {
System.Diagnostics.Debug.WriteLine("Scroll to " + index); System.Diagnostics.Debug.WriteLine("Scroll to " + index);
var layoutManager = ((TopLevel)VisualRoot).LayoutManager; var layoutManager = ((TopLevel)VisualRoot!).LayoutManager;
var element = _repeater.GetOrCreateElement(index); var element = _repeater.GetOrCreateElement(index);
layoutManager.ExecuteLayoutPass(); layoutManager.ExecuteLayoutPass();
element.BringIntoView(); element.BringIntoView();
@ -123,9 +125,11 @@ namespace ControlCatalog.Pages
private void RepeaterClick(object sender, PointerPressedEventArgs e) private void RepeaterClick(object sender, PointerPressedEventArgs e)
{ {
var item = (e.Source as TextBlock)?.DataContext as ItemsRepeaterPageViewModel.Item; if ((e.Source as TextBlock)?.DataContext is ItemsRepeaterPageViewModel.Item item)
_viewModel.SelectedItem = item; {
_selectedIndex = _viewModel.Items.IndexOf(item); _viewModel.SelectedItem = item;
_selectedIndex = _viewModel.Items.IndexOf(item);
}
} }
private void RepeaterOnKeyDown(object sender, KeyEventArgs e) private void RepeaterOnKeyDown(object sender, KeyEventArgs e)

2
samples/ControlCatalog/Pages/LabelsPage.axaml.cs

@ -7,7 +7,7 @@ namespace ControlCatalog.Pages
{ {
public class LabelsPage : UserControl public class LabelsPage : UserControl
{ {
private Person _person; private Person? _person;
public LabelsPage() public LabelsPage()
{ {

2
samples/ControlCatalog/Pages/MenuPage.xaml.cs

@ -22,7 +22,7 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
private MenuPageViewModel _model; private MenuPageViewModel? _model;
protected override void OnDataContextChanged(EventArgs e) protected override void OnDataContextChanged(EventArgs e)
{ {
if (_model != null) if (_model != null)

2
samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs

@ -79,6 +79,8 @@ namespace ControlCatalog.Pages
public interface INativeDemoControl public interface INativeDemoControl
{ {
/// <param name="isSecond">Used to specify which control should be displayed as a demo</param> /// <param name="isSecond">Used to specify which control should be displayed as a demo</param>
/// <param name="parent"></param>
/// <param name="createDefault"></param>
IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault); IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault);
} }
} }

2
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -65,7 +65,7 @@
Margin="2" HorizontalAlignment="Center"/> Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock> <TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock>
<NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding #upDown.Value}" VerticalAlignment="Center" <NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding DecimalValue}" VerticalAlignment="Center"
Margin="2" HorizontalAlignment="Center"/> Margin="2" HorizontalAlignment="Center"/>

10
samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs

@ -28,16 +28,16 @@ namespace ControlCatalog.Pages
public class NumbersPageViewModel : ViewModelBase public class NumbersPageViewModel : ViewModelBase
{ {
private IList<FormatObject> _formats; private IList<FormatObject>? _formats;
private FormatObject _selectedFormat; private FormatObject _selectedFormat;
private IList<Location> _spinnerLocations; private IList<Location>? _spinnerLocations;
private double _doubleValue; private double _doubleValue;
private decimal _decimalValue; private decimal _decimalValue;
public NumbersPageViewModel() public NumbersPageViewModel()
{ {
SelectedFormat = Formats.FirstOrDefault(); _selectedFormat = Formats.FirstOrDefault();
} }
public double DoubleValue public double DoubleValue
@ -103,7 +103,7 @@ namespace ControlCatalog.Pages
public class FormatObject public class FormatObject
{ {
public string Value { get; set; } public string? Value { get; set; }
public string Name { get; set; } public string? Name { get; set; }
} }
} }

2
samples/ControlCatalog/Pages/ScreenPage.cs

@ -18,7 +18,7 @@ namespace ControlCatalog.Pages
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
Window w = (Window)VisualRoot; Window w = (Window)VisualRoot!;
w.PositionChanged += (sender, args) => InvalidateVisual(); w.PositionChanged += (sender, args) => InvalidateVisual();
} }

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

@ -52,7 +52,7 @@ namespace ControlCatalog.Pages
private IBitmap LoadBitmap(string uri) private IBitmap LoadBitmap(string uri)
{ {
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>(); var assets = AvaloniaLocator.Current!.GetService<IAssetLoader>()!;
return new Bitmap(assets.Open(new Uri(uri))); return new Bitmap(assets.Open(new Uri(uri)));
} }
@ -60,7 +60,7 @@ namespace ControlCatalog.Pages
{ {
private Dock _tabPlacement; private Dock _tabPlacement;
public TabItemViewModel[] Tabs { get; set; } public TabItemViewModel[]? Tabs { get; set; }
public Dock TabPlacement public Dock TabPlacement
{ {
@ -71,10 +71,10 @@ namespace ControlCatalog.Pages
private class TabItemViewModel private class TabItemViewModel
{ {
public string Header { get; set; } public string? Header { get; set; }
public string Text { get; set; } public string? Text { get; set; }
public IBitmap Image { get; set; } public IBitmap? Image { get; set; }
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
} }
} }
} }

2
samples/ControlCatalog/Pages/TabStripPage.xaml.cs

@ -38,7 +38,7 @@ namespace ControlCatalog.Pages
private class TabStripItemViewModel private class TabStripItemViewModel
{ {
public string Header { get; set; } public string? Header { get; set; }
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
} }
} }

2
samples/ControlCatalog/ViewModels/ApplicationViewModel.cs

@ -10,7 +10,7 @@ namespace ControlCatalog.ViewModels
{ {
ExitCommand = MiniCommand.Create(() => ExitCommand = MiniCommand.Create(() =>
{ {
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
{ {
lifetime.Shutdown(); lifetime.Shutdown();
} }

2
samples/ControlCatalog/ViewModels/ContextPageViewModel.cs

@ -9,7 +9,7 @@ namespace ControlCatalog.ViewModels
{ {
public class ContextPageViewModel public class ContextPageViewModel
{ {
public Control View { get; set; } public Control? View { get; set; }
public ContextPageViewModel() public ContextPageViewModel()
{ {
OpenCommand = MiniCommand.CreateFromTask(Open); OpenCommand = MiniCommand.CreateFromTask(Open);

2
samples/ControlCatalog/ViewModels/CursorPageViewModel.cs

@ -18,7 +18,7 @@ namespace ControlCatalog.ViewModels
.Select(x => new StandardCursorModel(x)) .Select(x => new StandardCursorModel(x))
.ToList(); .ToList();
var loader = AvaloniaLocator.Current.GetService<IAssetLoader>(); var loader = AvaloniaLocator.Current!.GetService<IAssetLoader>()!;
var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png")); var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png"));
var bitmap = new Bitmap(s); var bitmap = new Bitmap(s);
CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16)); CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16));

19
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs

@ -14,7 +14,7 @@ namespace ControlCatalog.ViewModels
public ItemsRepeaterPageViewModel() public ItemsRepeaterPageViewModel()
{ {
Items = CreateItems(); _items = CreateItems();
} }
public ObservableCollection<Item> Items public ObservableCollection<Item> Items
@ -23,12 +23,12 @@ namespace ControlCatalog.ViewModels
set => this.RaiseAndSetIfChanged(ref _items, value); set => this.RaiseAndSetIfChanged(ref _items, value);
} }
public Item SelectedItem { get; set; } public Item? SelectedItem { get; set; }
public void AddItem() public void AddItem()
{ {
var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1; var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1;
Items.Insert(index + 1, new Item(index + 1) { Text = $"New Item {_newItemIndex++}" }); Items.Insert(index + 1, new Item(index + 1, $"New Item {_newItemIndex++}"));
} }
public void RemoveItem() public void RemoveItem()
@ -66,19 +66,20 @@ namespace ControlCatalog.ViewModels
_newGenerationIndex++; _newGenerationIndex++;
return new ObservableCollection<Item>( return new ObservableCollection<Item>(
Enumerable.Range(1, 100000).Select(i => new Item(i) Enumerable.Range(1, 100000).Select(i => new Item(i, $"Item {i.ToString()} {suffix}")));
{
Text = $"Item {i.ToString()} {suffix}"
}));
} }
public class Item : ViewModelBase public class Item : ViewModelBase
{ {
private double _height = double.NaN; private double _height = double.NaN;
public Item(int index) => Index = index; public Item(int index, string text)
{
Index = index;
Text = text;
}
public int Index { get; } public int Index { get; }
public string Text { get; set; } public string Text { get; }
public double Height public double Height
{ {

13
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -16,11 +16,11 @@ namespace ControlCatalog.ViewModels
private bool _isMenuItemChecked = true; private bool _isMenuItemChecked = true;
private WindowState _windowState; private WindowState _windowState;
private WindowState[] _windowStates; private WindowState[] _windowStates = Array.Empty<WindowState>();
private int _transparencyLevel; private int _transparencyLevel;
private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome; private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome;
private bool _extendClientAreaEnabled; private bool _extendClientAreaEnabled;
private bool _systemTitleBarEnabled; private bool _systemTitleBarEnabled;
private bool _preferSystemChromeEnabled; private bool _preferSystemChromeEnabled;
private double _titleBarHeight; private double _titleBarHeight;
@ -47,14 +47,15 @@ namespace ControlCatalog.ViewModels
{ {
var dialog = new AboutAvaloniaDialog(); var dialog = new AboutAvaloniaDialog();
var mainWindow = (App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow; if ((App.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow is { } mainWindow)
{
await dialog.ShowDialog(mainWindow); await dialog.ShowDialog(mainWindow);
}
}); });
ExitCommand = MiniCommand.Create(() => ExitCommand = MiniCommand.Create(() =>
{ {
(App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown(); (App.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Shutdown();
}); });
ToggleMenuItemCheckedCommand = MiniCommand.Create(() => ToggleMenuItemCheckedCommand = MiniCommand.Create(() =>

8
samples/ControlCatalog/ViewModels/MenuItemViewModel.cs

@ -5,9 +5,9 @@ namespace ControlCatalog.ViewModels
{ {
public class MenuItemViewModel public class MenuItemViewModel
{ {
public string Header { get; set; } public string? Header { get; set; }
public ICommand Command { get; set; } public ICommand? Command { get; set; }
public object CommandParameter { get; set; } public object? CommandParameter { get; set; }
public IList<MenuItemViewModel> Items { get; set; } public IList<MenuItemViewModel>? Items { get; set; }
} }
} }

2
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@ -10,7 +10,7 @@ namespace ControlCatalog.ViewModels
{ {
public class MenuPageViewModel public class MenuPageViewModel
{ {
public Control View { get; set; } public Control? View { get; set; }
public MenuPageViewModel() public MenuPageViewModel()
{ {
OpenCommand = MiniCommand.CreateFromTask(Open); OpenCommand = MiniCommand.CreateFromTask(Open);

4
samples/ControlCatalog/ViewModels/NotificationViewModel.cs

@ -19,8 +19,8 @@ namespace ControlCatalog.ViewModels
}); });
} }
public string Title { get; set; } public string? Title { get; set; }
public string Message { get; set; } public string? Message { get; set; }
public MiniCommand YesCommand { get; } public MiniCommand YesCommand { get; }

16
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@ -19,7 +19,7 @@ namespace ControlCatalog.ViewModels
{ {
public TransitioningContentControlPageViewModel() public TransitioningContentControlPageViewModel()
{ {
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>(); var assetLoader = AvaloniaLocator.Current?.GetService<IAssetLoader>()!;
var images = new string[] var images = new string[]
{ {
@ -36,8 +36,8 @@ namespace ControlCatalog.ViewModels
SetupTransitions(); SetupTransitions();
SelectedTransition = PageTransitions[1]; _SelectedTransition = PageTransitions[1];
SelectedImage = Images[0]; _SelectedImage = Images[0];
} }
public List<PageTransition> PageTransitions { get; } = new List<PageTransition>(); public List<PageTransition> PageTransitions { get; } = new List<PageTransition>();
@ -45,12 +45,12 @@ namespace ControlCatalog.ViewModels
public List<Bitmap> Images { get; } = new List<Bitmap>(); public List<Bitmap> Images { get; } = new List<Bitmap>();
private Bitmap? _SelectedImage; private Bitmap _SelectedImage;
/// <summary> /// <summary>
/// Gets or Sets the selected image /// Gets or Sets the selected image
/// </summary> /// </summary>
public Bitmap? SelectedImage public Bitmap SelectedImage
{ {
get { return _SelectedImage; } get { return _SelectedImage; }
set { this.RaiseAndSetIfChanged(ref _SelectedImage, value); } set { this.RaiseAndSetIfChanged(ref _SelectedImage, value); }
@ -160,12 +160,12 @@ namespace ControlCatalog.ViewModels
public string DisplayTitle { get; } public string DisplayTitle { get; }
private IPageTransition _Transition; private IPageTransition? _Transition;
/// <summary> /// <summary>
/// Gets or sets the transition /// Gets or sets the transition
/// </summary> /// </summary>
public IPageTransition Transition public IPageTransition? Transition
{ {
get { return _Transition; } get { return _Transition; }
set { this.RaiseAndSetIfChanged(ref _Transition, value); } set { this.RaiseAndSetIfChanged(ref _Transition, value); }
@ -201,7 +201,7 @@ namespace ControlCatalog.ViewModels
/// </summary> /// </summary>
public TimeSpan Duration { get; set; } public TimeSpan Duration { get; set; }
public async Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken) public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {

4
samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs

@ -92,7 +92,7 @@ namespace ControlCatalog.ViewModels
public class Node public class Node
{ {
private ObservableCollection<Node> _children; private ObservableCollection<Node>? _children;
private int _childIndex = 10; private int _childIndex = 10;
public Node() public Node()
@ -106,7 +106,7 @@ namespace ControlCatalog.ViewModels
Header = parent.Header + ' ' + index; Header = parent.Header + ' ' + index;
} }
public Node Parent { get; } public Node? Parent { get; }
public string Header { get; } public string Header { get; }
public bool AreChildrenInitialized => _children != null; public bool AreChildrenInitialized => _children != null;
public ObservableCollection<Node> Children => _children ??= CreateChildren(); public ObservableCollection<Node> Children => _children ??= CreateChildren();

4
samples/RenderDemo/Pages/FormattedTextPage.axaml.cs

@ -55,6 +55,10 @@ namespace RenderDemo.Pages
formattedText.SetFontStyle(FontStyle.Italic, 28, 28); formattedText.SetFontStyle(FontStyle.Italic, 28, 28);
context.DrawText(formattedText, new Point(10, 0)); context.DrawText(formattedText, new Point(10, 0));
var geometry = formattedText.BuildGeometry(new Point(10 + formattedText.Width + 10, 0));
context.DrawGeometry(gradient, null, geometry);
} }
} }
} }

12
samples/RenderDemo/Pages/GlyphRunPage.xaml

@ -2,13 +2,13 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RenderDemo.Pages"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="RenderDemo.Pages.GlyphRunPage"> x:Class="RenderDemo.Pages.GlyphRunPage">
<Border <Grid
ColumnDefinitions="*,*"
Background="White"> Background="White">
<Image <local:GlyphRunControl Grid.Column="0"/>
x:Name="imageControl" <local:GlyphRunGeometryControl Grid.Column="1"/>
Stretch="None"> </Grid>
</Image>
</Border>
</UserControl> </UserControl>

113
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -9,14 +9,6 @@ namespace RenderDemo.Pages
{ {
public class GlyphRunPage : UserControl public class GlyphRunPage : UserControl
{ {
private Image _imageControl;
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
private float _fontSize = 20;
private int _direction = 10;
public GlyphRunPage() public GlyphRunPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
@ -25,19 +17,43 @@ namespace RenderDemo.Pages
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
}
}
public class GlyphRunControl : Control
{
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
private float _fontSize = 20;
private int _direction = 10;
_imageControl = this.FindControl<Image>("imageControl"); private DispatcherTimer _timer;
_imageControl.Source = new DrawingImage();
DispatcherTimer.Run(() => protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
_timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
_timer.Tick += (s,e) =>
{ {
UpdateGlyphRun(); InvalidateVisual();
};
_timer.Start();
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_timer.Stop();
return true; _timer = null;
}, TimeSpan.FromSeconds(1));
} }
private void UpdateGlyphRun() public override void Render(DrawingContext context)
{ {
var c = (char)_rand.Next(65, 90); var c = (char)_rand.Next(65, 90);
@ -57,27 +73,70 @@ namespace RenderDemo.Pages
_characters[0] = c; _characters[0] = c;
var scale = (double)_fontSize / _glyphTypeface.DesignEmHeight; var glyphRun = new GlyphRun(_glyphTypeface, _fontSize, _characters, _glyphIndices);
var drawingGroup = new DrawingGroup(); context.DrawGlyphRun(Brushes.Black, glyphRun);
}
}
var glyphRunDrawing = new GlyphRunDrawing public class GlyphRunGeometryControl : Control
{
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
private float _fontSize = 20;
private int _direction = 10;
private DispatcherTimer _timer;
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
_timer = new DispatcherTimer
{ {
Foreground = Brushes.Black, Interval = TimeSpan.FromSeconds(1)
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _characters, _glyphIndices)
}; };
drawingGroup.Children.Add(glyphRunDrawing); _timer.Tick += (s, e) =>
var geometryDrawing = new GeometryDrawing
{ {
Pen = new Pen(Brushes.Black), InvalidateVisual();
Geometry = new RectangleGeometry { Rect = new Rect(glyphRunDrawing.GlyphRun.Size) }
}; };
drawingGroup.Children.Add(geometryDrawing); _timer.Start();
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_timer.Stop();
_timer = null;
}
public override void Render(DrawingContext context)
{
var c = (char)_rand.Next(65, 90);
if (_fontSize + _direction > 200)
{
_direction = -10;
}
if (_fontSize + _direction < 20)
{
_direction = 10;
}
_fontSize += _direction;
_glyphIndices[0] = _glyphTypeface.GetGlyph(c);
_characters[0] = c;
var glyphRun = new GlyphRun(_glyphTypeface, _fontSize, _characters, _glyphIndices);
var geometry = glyphRun.BuildGeometry();
(_imageControl.Source as DrawingImage).Drawing = drawingGroup; context.DrawGeometry(Brushes.Green, null, geometry);
} }
} }
} }

2
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -61,8 +61,6 @@ namespace Avalonia.Android
.Bind<IRenderLoop>().ToConstant(new RenderLoop()) .Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>(); .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
SkiaPlatform.Initialize();
if (options.UseGpu) if (options.UseGpu)
{ {
EglPlatformOpenGlInterface.TryInitialize(); EglPlatformOpenGlInterface.TryInitialize();

7
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -31,21 +31,22 @@ namespace Avalonia.Android
CustomizeAppBuilder(builder); CustomizeAppBuilder(builder);
View = new AvaloniaView(this);
SetContentView(View);
var lifetime = new SingleViewLifetime(); var lifetime = new SingleViewLifetime();
lifetime.View = View;
builder.AfterSetup(x => builder.AfterSetup(x =>
{ {
_viewModel = new ViewModelProvider(this).Get(Java.Lang.Class.FromType(typeof(AvaloniaViewModel))) as AvaloniaViewModel; _viewModel = new ViewModelProvider(this).Get(Java.Lang.Class.FromType(typeof(AvaloniaViewModel))) as AvaloniaViewModel;
View = new AvaloniaView(this);
if (_viewModel.Content != null) if (_viewModel.Content != null)
{ {
View.Content = _viewModel.Content; View.Content = _viewModel.Content;
} }
SetContentView(View);
lifetime.View = View;
View.Prepare(); View.Prepare();
}); });

2
src/Android/Avalonia.Android/AvaloniaView.cs

@ -15,7 +15,7 @@ namespace Avalonia.Android
private EmbeddableControlRoot _root; private EmbeddableControlRoot _root;
private readonly ViewImpl _view; private readonly ViewImpl _view;
private IDisposable? _timerSubscription; private IDisposable _timerSubscription;
public AvaloniaView(Context context) : base(context) public AvaloniaView(Context context) : base(context)
{ {

2
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -30,7 +30,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return DispatchKeyEventInternal(e, out callBase); return DispatchKeyEventInternal(e, out callBase);
} }
string? UnicodeTextInput(KeyEvent keyEvent) string UnicodeTextInput(KeyEvent keyEvent)
{ {
return keyEvent.Action == KeyEventActions.Multiple return keyEvent.Action == KeyEventActions.Multiple
&& keyEvent.RepeatCount == 0 && keyEvent.RepeatCount == 0

BIN
src/Avalonia.Base/Assets/BiDi.trie

Binary file not shown.

BIN
src/Avalonia.Base/Assets/GraphemeBreak.trie

Binary file not shown.

BIN
src/Avalonia.Base/Assets/UnicodeData.trie

Binary file not shown.

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -28,7 +28,6 @@
<InternalsVisibleTo Include="Avalonia.Direct2D1.RenderTests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.Direct2D1.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.LeakTests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.LeakTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml.UnitTests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.Markup.Xaml.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.PlatformSupport, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia.RenderTests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.Skia.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia.UnitTests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.Skia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" /> <InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />

37
src/Avalonia.Base/GeometryCollection.cs

@ -1,37 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Avalonia.Animation;
#nullable enable
namespace Avalonia.Media
{
public class GeometryCollection : Animatable, IList<Geometry>, IReadOnlyList<Geometry>
{
private List<Geometry> _inner;
public GeometryCollection() => _inner = new List<Geometry>();
public GeometryCollection(IEnumerable<Geometry> collection) => _inner = new List<Geometry>(collection);
public GeometryCollection(int capacity) => _inner = new List<Geometry>(capacity);
public Geometry this[int index]
{
get => _inner[index];
set => _inner[index] = value;
}
public int Count => _inner.Count;
public bool IsReadOnly => false;
public void Add(Geometry item) => _inner.Add(item);
public void Clear() => _inner.Clear();
public bool Contains(Geometry item) => _inner.Contains(item);
public void CopyTo(Geometry[] array, int arrayIndex) => _inner.CopyTo(array, arrayIndex);
public IEnumerator<Geometry> GetEnumerator() => _inner.GetEnumerator();
public int IndexOf(Geometry item) => _inner.IndexOf(item);
public void Insert(int index, Geometry item) => _inner.Insert(index, item);
public bool Remove(Geometry item) => _inner.Remove(item);
public void RemoveAt(int index) => _inner.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}

14
src/Avalonia.Base/Layout/LayoutManager.cs

@ -28,7 +28,7 @@ namespace Avalonia.Layout
public LayoutManager(ILayoutRoot owner) public LayoutManager(ILayoutRoot owner)
{ {
_owner = owner ?? throw new ArgumentNullException(nameof(owner)); _owner = owner ?? throw new ArgumentNullException(nameof(owner));
_executeLayoutPass = ExecuteLayoutPass; _executeLayoutPass = ExecuteQueuedLayoutPass;
} }
public virtual event EventHandler? LayoutUpdated; public virtual event EventHandler? LayoutUpdated;
@ -94,6 +94,16 @@ namespace Avalonia.Layout
QueueLayoutPass(); QueueLayoutPass();
} }
private void ExecuteQueuedLayoutPass()
{
if (!_queued)
{
return;
}
ExecuteLayoutPass();
}
/// <inheritdoc/> /// <inheritdoc/>
public virtual void ExecuteLayoutPass() public virtual void ExecuteLayoutPass()
{ {
@ -319,8 +329,8 @@ namespace Avalonia.Layout
{ {
if (!_queued && !_running) if (!_queued && !_running)
{ {
Dispatcher.UIThread.Post(_executeLayoutPass, DispatcherPriority.Layout);
_queued = true; _queued = true;
Dispatcher.UIThread.Post(_executeLayoutPass, DispatcherPriority.Layout);
} }
} }

76
src/Avalonia.Base/Matrix.cs

@ -9,14 +9,14 @@ namespace Avalonia
/// <summary> /// <summary>
/// A 3x3 matrix. /// A 3x3 matrix.
/// </summary> /// </summary>
/// <remakrs>Matrix layout: /// <remarks>Matrix layout:
/// | 1st col | 2nd col | 3r col | /// | 1st col | 2nd col | 3r col |
/// 1st row | scaleX | skrewY | persX | /// 1st row | scaleX | skewY | perspX |
/// 2nd row | skrewX | scaleY | persY | /// 2nd row | skewX | scaleY | perspY |
/// 3rd row | transX | transY | persZ | /// 3rd row | transX | transY | perspZ |
/// ///
/// Note: Skia.SkMatrix uses a transposed layout (where for example skrewX/skrewY and perspp0/tranX are swapped). /// Note: Skia.SkMatrix uses a transposed layout (where for example skewX/skewY and persp0/transX are swapped).
/// </remakrs> /// </remarks>
#if !BUILDTASK #if !BUILDTASK
public public
#endif #endif
@ -36,18 +36,18 @@ namespace Avalonia
/// Initializes a new instance of the <see cref="Matrix"/> struct (equivalent to a 2x3 Matrix without perspective). /// Initializes a new instance of the <see cref="Matrix"/> struct (equivalent to a 2x3 Matrix without perspective).
/// </summary> /// </summary>
/// <param name="scaleX">The first element of the first row.</param> /// <param name="scaleX">The first element of the first row.</param>
/// <param name="skrewY">The second element of the first row.</param> /// <param name="skewY">The second element of the first row.</param>
/// <param name="skrewX">The first element of the second row.</param> /// <param name="skewX">The first element of the second row.</param>
/// <param name="scaleY">The second element of the second row.</param> /// <param name="scaleY">The second element of the second row.</param>
/// <param name="offsetX">The first element of the third row.</param> /// <param name="offsetX">The first element of the third row.</param>
/// <param name="offsetY">The second element of the third row.</param> /// <param name="offsetY">The second element of the third row.</param>
public Matrix( public Matrix(
double scaleX, double scaleX,
double skrewY, double skewY,
double skrewX, double skewX,
double scaleY, double scaleY,
double offsetX, double offsetX,
double offsetY) : this( scaleX, skrewY, 0, skrewX, scaleY, 0, offsetX, offsetY, 1) double offsetY) : this( scaleX, skewY, 0, skewX, scaleY, 0, offsetX, offsetY, 1)
{ {
} }
@ -57,34 +57,34 @@ namespace Avalonia
/// Initializes a new instance of the <see cref="Matrix"/> struct. /// Initializes a new instance of the <see cref="Matrix"/> struct.
/// </summary> /// </summary>
/// <param name="scaleX">The first element of the first row.</param> /// <param name="scaleX">The first element of the first row.</param>
/// <param name="skrewY">The second element of the first row.</param> /// <param name="skewY">The second element of the first row.</param>
/// <param name="persX">The third element of the first row.</param> /// <param name="perspX">The third element of the first row.</param>
/// <param name="skrewX">The first element of the second row.</param> /// <param name="skewX">The first element of the second row.</param>
/// <param name="scaleY">The second element of the second row.</param> /// <param name="scaleY">The second element of the second row.</param>
/// <param name="persY">The third element of the second row.</param> /// <param name="perspY">The third element of the second row.</param>
/// <param name="offsetX">The first element of the third row.</param> /// <param name="offsetX">The first element of the third row.</param>
/// <param name="offsetY">The second element of the third row.</param> /// <param name="offsetY">The second element of the third row.</param>
/// <param name="persZ">The third element of the third row.</param> /// <param name="perspZ">The third element of the third row.</param>
public Matrix( public Matrix(
double scaleX, double scaleX,
double skrewY, double skewY,
double persX, double perspX,
double skrewX, double skewX,
double scaleY, double scaleY,
double persY, double perspY,
double offsetX, double offsetX,
double offsetY, double offsetY,
double persZ) double perspZ)
{ {
_m11 = scaleX; _m11 = scaleX;
_m12 = skrewY; _m12 = skewY;
_m13 = persX; _m13 = perspX;
_m21 = skrewX; _m21 = skewX;
_m22 = scaleY; _m22 = scaleY;
_m23 = persY; _m23 = perspY;
_m31 = offsetX; _m31 = offsetX;
_m32 = offsetY; _m32 = offsetY;
_m33 = persZ; _m33 = perspZ;
} }
/// <summary> /// <summary>
@ -111,17 +111,17 @@ namespace Avalonia
public double M11 => _m11; public double M11 => _m11;
/// <summary> /// <summary>
/// The second element of the first row (skrewY). /// The second element of the first row (skewY).
/// </summary> /// </summary>
public double M12 => _m12; public double M12 => _m12;
/// <summary> /// <summary>
/// The third element of the first row (persX: input x-axis perspective factor). /// The third element of the first row (perspX: input x-axis perspective factor).
/// </summary> /// </summary>
public double M13 => _m13; public double M13 => _m13;
/// <summary> /// <summary>
/// The first element of the second row (skrewX). /// The first element of the second row (skewX).
/// </summary> /// </summary>
public double M21 => _m21; public double M21 => _m21;
@ -131,7 +131,7 @@ namespace Avalonia
public double M22 => _m22; public double M22 => _m22;
/// <summary> /// <summary>
/// The third element of the second row (persY: input y-axis perspective factor). /// The third element of the second row (perspY: input y-axis perspective factor).
/// </summary> /// </summary>
public double M23 => _m23; public double M23 => _m23;
@ -146,7 +146,7 @@ namespace Avalonia
public double M32 => _m32; public double M32 => _m32;
/// <summary> /// <summary>
/// The third element of the third row (persZ: perspective scale factor). /// The third element of the third row (perspZ: perspective scale factor).
/// </summary> /// </summary>
public double M33 => _m33; public double M33 => _m33;
@ -450,13 +450,13 @@ namespace Avalonia
inverted = new Matrix( inverted = new Matrix(
(_m22 * _m33 - _m32 * _m23) * invdet, (_m22 * _m33 - _m32 * _m23) * invdet,
(_m13 * _m31 - _m12 * _m33) * invdet, (_m13 * _m32 - _m12 * _m33) * invdet,
(_m12 * _m23 - _m13 * _m22) * invdet, (_m12 * _m23 - _m13 * _m22) * invdet,
(_m23 * _m31 - _m21 * _m33) * invdet, (_m23 * _m31 - _m21 * _m33) * invdet,
(_m11 * _m33 - _m13 * _m31) * invdet, (_m11 * _m33 - _m13 * _m31) * invdet,
(_m21 * _m13 - _m11 * _m23) * invdet, (_m21 * _m13 - _m11 * _m23) * invdet,
(_m21 * _m32 - _m31 * _m22) * invdet, (_m21 * _m32 - _m31 * _m22) * invdet,
(_m21 * _m12 - _m11 * _m32) * invdet, (_m31 * _m12 - _m11 * _m32) * invdet,
(_m11 * _m22 - _m21 * _m12) * invdet (_m11 * _m22 - _m21 * _m12) * invdet
); );
@ -481,7 +481,7 @@ namespace Avalonia
/// <summary> /// <summary>
/// Parses a <see cref="Matrix"/> string. /// Parses a <see cref="Matrix"/> string.
/// </summary> /// </summary>
/// <param name="s">Six or nine comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY[, persX, persY, persZ]) that describe the new <see cref="Matrix"/></param> /// <param name="s">Six or nine comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY[, perspX, perspY, perspZ]) that describe the new <see cref="Matrix"/></param>
/// <returns>The <see cref="Matrix"/>.</returns> /// <returns>The <see cref="Matrix"/>.</returns>
public static Matrix Parse(string s) public static Matrix Parse(string s)
{ {
@ -497,11 +497,11 @@ namespace Avalonia
var v4 = tokenizer.ReadDouble(); var v4 = tokenizer.ReadDouble();
var v5 = tokenizer.ReadDouble(); var v5 = tokenizer.ReadDouble();
var v6 = tokenizer.ReadDouble(); var v6 = tokenizer.ReadDouble();
var pers = tokenizer.TryReadDouble(out var v7); var persp = tokenizer.TryReadDouble(out var v7);
pers = pers && tokenizer.TryReadDouble(out v8); persp = persp && tokenizer.TryReadDouble(out v8);
pers = pers && tokenizer.TryReadDouble(out v9); persp = persp && tokenizer.TryReadDouble(out v9);
if (pers) if (persp)
return new Matrix(v1, v2, v7, v3, v4, v8, v5, v6, v9); return new Matrix(v1, v2, v7, v3, v4, v8, v5, v6, v9);
else else
return new Matrix(v1, v2, v3, v4, v5, v6); return new Matrix(v1, v2, v3, v4, v5, v6);

18
src/Avalonia.Base/Media/DrawingCollection.cs

@ -0,0 +1,18 @@
using System.Collections.Generic;
using Avalonia.Collections;
namespace Avalonia.Media
{
public sealed class DrawingCollection : AvaloniaList<Drawing>
{
public DrawingCollection()
{
ResetBehavior = ResetBehavior.Remove;
}
public DrawingCollection(IEnumerable<Drawing> items) : base(items)
{
ResetBehavior = ResetBehavior.Remove;
}
}
}

420
src/Avalonia.Base/Media/DrawingGroup.cs

@ -1,6 +1,10 @@
using Avalonia.Collections; using System;
using System.Collections.Generic;
using Avalonia.Media.Imaging;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities;
namespace Avalonia.Media namespace Avalonia.Media
{ {
@ -18,6 +22,14 @@ namespace Avalonia.Media
public static readonly StyledProperty<IBrush> OpacityMaskProperty = public static readonly StyledProperty<IBrush> OpacityMaskProperty =
AvaloniaProperty.Register<DrawingGroup, IBrush>(nameof(OpacityMask)); AvaloniaProperty.Register<DrawingGroup, IBrush>(nameof(OpacityMask));
public static readonly DirectProperty<DrawingGroup, DrawingCollection> ChildrenProperty =
AvaloniaProperty.RegisterDirect<DrawingGroup, DrawingCollection>(
nameof(Children),
o => o.Children,
(o, v) => o.Children = v);
private DrawingCollection _children = new DrawingCollection();
public double Opacity public double Opacity
{ {
get => GetValue(OpacityProperty); get => GetValue(OpacityProperty);
@ -42,8 +54,23 @@ namespace Avalonia.Media
set => SetValue(OpacityMaskProperty, value); set => SetValue(OpacityMaskProperty, value);
} }
/// <summary>
/// Gets or sets the collection that contains the child geometries.
/// </summary>
[Content] [Content]
public AvaloniaList<Drawing> Children { get; } = new AvaloniaList<Drawing>(); public DrawingCollection Children
{
get => _children;
set
{
SetAndRaise(ChildrenProperty, ref _children, value);
}
}
public DrawingContext Open()
{
return new DrawingContext(new DrawingGroupDrawingContext(this));
}
public override void Draw(DrawingContext context) public override void Draw(DrawingContext context)
{ {
@ -75,5 +102,394 @@ namespace Avalonia.Media
return rect; return rect;
} }
private class DrawingGroupDrawingContext : IDrawingContextImpl
{
private readonly DrawingGroup _drawingGroup;
private readonly IPlatformRenderInterface _platformRenderInterface = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
private Matrix _transform;
private bool _disposed;
// Root drawing created by this DrawingContext.
//
// If there is only a single child of the root DrawingGroup, _rootDrawing
// will reference the single child, and the root _currentDrawingGroup
// value will be null. Otherwise, _rootDrawing will reference the
// root DrawingGroup, and be the same value as the root _currentDrawingGroup.
//
// Either way, _rootDrawing always references the root drawing.
protected Drawing? _rootDrawing;
// Current DrawingGroup that new children are added to
protected DrawingGroup? _currentDrawingGroup;
// Previous values of _currentDrawingGroup
private Stack<DrawingGroup?>? _previousDrawingGroupStack;
public DrawingGroupDrawingContext(DrawingGroup drawingGroup)
{
_drawingGroup = drawingGroup;
}
public Matrix Transform
{
get => _transform;
set
{
_transform = value;
PushTransform(new MatrixTransform(value));
}
}
public void DrawEllipse(IBrush? brush, IPen? pen, Rect rect)
{
if ((brush == null) && (pen == null))
{
return;
}
// Instantiate the geometry
var geometry = _platformRenderInterface.CreateEllipseGeometry(rect);
// Add Drawing to the Drawing graph
AddNewGeometryDrawing(brush, pen, new PlatformGeometry(geometry));
}
public void DrawGeometry(IBrush? brush, IPen? pen, IGeometryImpl geometry)
{
if (((brush == null) && (pen == null)) || (geometry == null))
{
return;
}
AddNewGeometryDrawing(brush, pen, new PlatformGeometry(geometry));
}
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
if (foreground == null || glyphRun == null)
{
return;
}
// Add a GlyphRunDrawing to the Drawing graph
GlyphRunDrawing glyphRunDrawing = new GlyphRunDrawing
{
Foreground = foreground,
GlyphRun = glyphRun,
};
// Add Drawing to the Drawing graph
AddDrawing(glyphRunDrawing);
}
public void DrawLine(IPen pen, Point p1, Point p2)
{
if (pen == null)
{
return;
}
// Instantiate the geometry
var geometry = _platformRenderInterface.CreateLineGeometry(p1, p2);
// Add Drawing to the Drawing graph
AddNewGeometryDrawing(null, pen, new PlatformGeometry(geometry));
}
public void DrawRectangle(IBrush? brush, IPen? pen, RoundedRect rect, BoxShadows boxShadows = default)
{
if ((brush == null) && (pen == null))
{
return;
}
// Instantiate the geometry
var geometry = _platformRenderInterface.CreateRectangleGeometry(rect.Rect);
// Add Drawing to the Drawing graph
AddNewGeometryDrawing(brush, pen, new PlatformGeometry(geometry));
}
public void Clear(Color color)
{
throw new NotImplementedException();
}
public IDrawingContextLayerImpl CreateLayer(Size size)
{
throw new NotImplementedException();
}
public void Custom(ICustomDrawOperation custom)
{
throw new NotImplementedException();
}
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
{
throw new NotImplementedException();
}
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
{
throw new NotImplementedException();
}
public void PopBitmapBlendMode()
{
throw new NotImplementedException();
}
public void PopClip()
{
throw new NotImplementedException();
}
public void PopGeometryClip()
{
throw new NotImplementedException();
}
public void PopOpacity()
{
throw new NotImplementedException();
}
public void PopOpacityMask()
{
throw new NotImplementedException();
}
public void PushBitmapBlendMode(BitmapBlendingMode blendingMode)
{
throw new NotImplementedException();
}
public void PushClip(Rect clip)
{
throw new NotImplementedException();
}
public void PushClip(RoundedRect clip)
{
throw new NotImplementedException();
}
public void PushGeometryClip(IGeometryImpl clip)
{
throw new NotImplementedException();
}
public void PushOpacity(double opacity)
{
throw new NotImplementedException();
}
public void PushOpacityMask(IBrush mask, Rect bounds)
{
throw new NotImplementedException();
}
public void Dispose()
{
// Dispose may be called multiple times without throwing
// an exception.
if (!_disposed)
{
// Match any outstanding Push calls with a Pop
if (_previousDrawingGroupStack != null)
{
int stackCount = _previousDrawingGroupStack.Count;
for (int i = 0; i < stackCount; i++)
{
Pop();
}
}
// Call CloseCore with the root DrawingGroup's children
DrawingCollection rootChildren;
if (_currentDrawingGroup != null)
{
// If we created a root DrawingGroup because multiple elements
// exist at the root level, provide it's Children collection
// directly.
rootChildren = _currentDrawingGroup.Children;
}
else
{
// Create a new DrawingCollection if we didn't create a
// root DrawingGroup because the root level only contained
// a single child.
//
// This collection is needed by DrawingGroup.Open because
// Open always replaces it's Children collection. It isn't
// strictly needed for Append, but always using a collection
// simplifies the TransactionalAppend implementation (i.e.,
// a seperate implemention isn't needed for a single element)
rootChildren = new DrawingCollection();
//
// We may need to opt-out of inheritance through the new Freezable.
// This is controlled by this.CanBeInheritanceContext.
//
if (_rootDrawing != null)
{
rootChildren.Add(_rootDrawing);
}
}
// Inform our derived classes that Close was called
_drawingGroup.Children = rootChildren;
_disposed = true;
}
}
/// <summary>
/// Pop
/// </summary>
private void Pop()
{
// Verify that Pop hasn't been called too many times
if ((_previousDrawingGroupStack == null) || (_previousDrawingGroupStack.Count == 0))
{
throw new InvalidOperationException("DrawingGroupStack count missmatch.");
}
// Restore the previous value of the current drawing group
_currentDrawingGroup = _previousDrawingGroupStack.Pop();
}
/// <summary>
/// PushTransform -
/// Push a Transform which will apply to all drawing operations until the corresponding
/// Pop.
/// </summary>
/// <param name="transform"> The Transform to push. </param>
private void PushTransform(Transform transform)
{
// Instantiate a new drawing group and set it as the _currentDrawingGroup
var drawingGroup = PushNewDrawingGroup();
// Set the transform on the new DrawingGroup
drawingGroup.Transform = transform;
}
/// <summary>
/// Creates a new DrawingGroup for a Push* call by setting the
/// _currentDrawingGroup to a newly instantiated DrawingGroup,
/// and saving the previous _currentDrawingGroup value on the
/// _previousDrawingGroupStack.
/// </summary>
private DrawingGroup PushNewDrawingGroup()
{
// Instantiate a new drawing group
DrawingGroup drawingGroup = new DrawingGroup();
// Add it to the drawing graph, like any other Drawing
AddDrawing(drawingGroup);
// Lazily allocate the stack when it is needed because many uses
// of DrawingDrawingContext will have a depth of one.
if (null == _previousDrawingGroupStack)
{
_previousDrawingGroupStack = new Stack<DrawingGroup?>(2);
}
// Save the previous _currentDrawingGroup value.
//
// If this is the first call, the value of _currentDrawingGroup
// will be null because AddDrawing doesn't create a _currentDrawingGroup
// for the first drawing. Having null on the stack is valid, and simply
// denotes that this new DrawingGroup is the first child in the root
// DrawingGroup. It is also possible for the first value on the stack
// to be non-null, which means that the root DrawingGroup has other
// children.
_previousDrawingGroupStack.Push(_currentDrawingGroup);
// Set this drawing group as the current one so that subsequent drawing's
// are added as it's children until Pop is called.
_currentDrawingGroup = drawingGroup;
return drawingGroup;
}
/// <summary>
/// Contains the functionality common to GeometryDrawing operations of
/// instantiating the GeometryDrawing, setting it's Freezable state,
/// and Adding it to the Drawing Graph.
/// </summary>
private void AddNewGeometryDrawing(IBrush? brush, IPen? pen, Geometry? geometry)
{
if (geometry == null)
{
throw new ArgumentNullException(nameof(geometry));
}
// Instantiate the GeometryDrawing
GeometryDrawing geometryDrawing = new GeometryDrawing
{
// We may need to opt-out of inheritance through the new Freezable.
// This is controlled by this.CanBeInheritanceContext.
Brush = brush,
Pen = pen,
Geometry = geometry
};
// Add it to the drawing graph
AddDrawing(geometryDrawing);
}
/// <summary>
/// Adds a new Drawing to the DrawingGraph.
///
/// This method avoids creating a DrawingGroup for the common case
/// where only a single child exists in the root DrawingGroup.
/// </summary>
private void AddDrawing(Drawing newDrawing)
{
if (newDrawing == null)
{
throw new ArgumentNullException(nameof(newDrawing));
}
if (_rootDrawing == null)
{
// When a DrawingGroup is set, it should be made the root if
// a root drawing didnt exist.
Contract.Requires<NotSupportedException>(_currentDrawingGroup == null);
// If this is the first Drawing being added, avoid creating a DrawingGroup
// and set this drawing as the root drawing. This optimizes the common
// case where only a single child exists in the root DrawingGroup.
_rootDrawing = newDrawing;
}
else if (_currentDrawingGroup == null)
{
// When the second drawing is added at the root level, set a
// DrawingGroup as the root and add both drawings to it.
// Instantiate the DrawingGroup
_currentDrawingGroup = new DrawingGroup();
// Add both Children
_currentDrawingGroup.Children.Add(_rootDrawing);
_currentDrawingGroup.Children.Add(newDrawing);
// Set the new DrawingGroup as the current
_rootDrawing = _currentDrawingGroup;
}
else
{
// If there already is a current drawing group, then simply add
// the new drawing too it.
_currentDrawingGroup.Children.Add(newDrawing);
}
}
}
} }
} }

129
src/Avalonia.Base/Media/FormattedText.cs

@ -1223,7 +1223,7 @@ namespace Avalonia.Media
public double OverhangTrailing public double OverhangTrailing
{ {
get get
{ {
return BlackBoxMetrics.OverhangTrailing; return BlackBoxMetrics.OverhangTrailing;
} }
} }
@ -1252,6 +1252,46 @@ namespace Avalonia.Media
} }
} }
/// <summary>
/// Obtains geometry for the text, including underlines and strikethroughs.
/// </summary>
/// <param name="origin">The left top origin of the resulting geometry.</param>
/// <returns>The geometry returned contains the combined geometry
/// of all of the glyphs, underlines and strikeThroughs that represent the formatted text.
/// Overlapping contours are merged by performing a Boolean union operation.</returns>
public Geometry? BuildGeometry(Point origin)
{
GeometryGroup? accumulatedGeometry = null;
var lineOrigin = origin;
DrawingGroup drawing = new DrawingGroup();
using (var ctx = drawing.Open())
{
using (var enumerator = GetEnumerator())
{
while (enumerator.MoveNext())
{
var currentLine = enumerator.Current;
if (currentLine != null)
{
currentLine.Draw(ctx, lineOrigin);
AdvanceLineOrigin(ref lineOrigin, currentLine);
}
}
}
}
Transform? transform = new TranslateTransform(origin.X, origin.Y);
// recursively go down the DrawingGroup to build up the geometry
CombineGeometryRecursive(drawing, ref transform, ref accumulatedGeometry);
return accumulatedGeometry;
}
/// <summary> /// <summary>
/// Draws the text object /// Draws the text object
/// </summary> /// </summary>
@ -1284,6 +1324,93 @@ namespace Avalonia.Media
} }
} }
private void CombineGeometryRecursive(Drawing drawing, ref Transform? transform, ref GeometryGroup? accumulatedGeometry)
{
if (drawing is DrawingGroup group)
{
transform = group.Transform;
if (group.Children is DrawingCollection children)
{
// recursively go down for DrawingGroup
foreach (var child in children)
{
CombineGeometryRecursive(child, ref transform, ref accumulatedGeometry);
}
}
}
else
{
if (drawing is GlyphRunDrawing glyphRunDrawing)
{
// process glyph run
var glyphRun = glyphRunDrawing.GlyphRun;
if (glyphRun != null)
{
var glyphRunGeometry = glyphRun.BuildGeometry();
glyphRunGeometry.Transform = transform;
if (accumulatedGeometry == null)
{
accumulatedGeometry = new GeometryGroup
{
FillRule = FillRule.NonZero
};
}
accumulatedGeometry.Children.Add(glyphRunGeometry);
}
}
else
{
if (drawing is GeometryDrawing geometryDrawing)
{
// process geometry (i.e. TextDecoration on the line)
var geometry = geometryDrawing.Geometry;
if (geometry != null)
{
geometry.Transform = transform;
if (geometry is LineGeometry lineGeometry)
{
// For TextDecoration drawn by DrawLine(), the geometry is a LineGeometry which has no
// bounding area. So this line won't show up. Work aroud it by increase the Bounding rect
// to be Pen's thickness
var bounds = lineGeometry.Bounds;
if (bounds.Height == 0)
{
bounds = bounds.WithHeight(geometryDrawing.Pen?.Thickness ?? 0);
}
else if (bounds.Width == 0)
{
bounds = bounds.WithWidth(geometryDrawing.Pen?.Thickness ?? 0);
}
// convert the line geometry into a rectangle geometry
// we lost line cap info here
geometry = new RectangleGeometry(bounds);
}
if (accumulatedGeometry == null)
{
accumulatedGeometry = new GeometryGroup
{
FillRule = FillRule.NonZero
};
}
accumulatedGeometry.Children.Add(geometry);
}
}
}
}
}
private CachedMetrics DrawAndCalculateMetrics(DrawingContext? drawingContext, Point drawingOffset, bool getBlackBoxMetrics) private CachedMetrics DrawAndCalculateMetrics(DrawingContext? drawingContext, Point drawingOffset, bool getBlackBoxMetrics)
{ {
var metrics = new CachedMetrics(); var metrics = new CachedMetrics();

45
src/Avalonia.Base/Media/GeometryCollection.cs

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using Avalonia.Collections;
#nullable enable
namespace Avalonia.Media
{
public sealed class GeometryCollection : AvaloniaList<Geometry>
{
public GeometryCollection()
{
ResetBehavior = ResetBehavior.Remove;
this.ForEachItem(
x =>
{
Parent?.Invalidate();
},
x =>
{
Parent?.Invalidate();
},
() => throw new NotSupportedException());
}
public GeometryCollection(IEnumerable<Geometry> items) : base(items)
{
ResetBehavior = ResetBehavior.Remove;
this.ForEachItem(
x =>
{
Parent?.Invalidate();
},
x =>
{
Parent?.Invalidate();
},
() => throw new NotSupportedException());
}
public GeometryGroup? Parent { get; set; }
}
}

15
src/Avalonia.Base/Media/GeometryDrawing.cs

@ -21,14 +21,14 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Defines the <see cref="Brush"/> property. /// Defines the <see cref="Brush"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IBrush> BrushProperty = public static readonly StyledProperty<IBrush?> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent); AvaloniaProperty.Register<GeometryDrawing, IBrush?>(nameof(Brush), Brushes.Transparent);
/// <summary> /// <summary>
/// Defines the <see cref="Pen"/> property. /// Defines the <see cref="Pen"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<Pen> PenProperty = public static readonly StyledProperty<Pen?> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen)); AvaloniaProperty.Register<GeometryDrawing, Pen?>(nameof(Pen));
/// <summary> /// <summary>
/// Gets or sets the <see cref="Avalonia.Media.Geometry"/> that describes the shape of this <see cref="GeometryDrawing"/>. /// Gets or sets the <see cref="Avalonia.Media.Geometry"/> that describes the shape of this <see cref="GeometryDrawing"/>.
@ -43,7 +43,7 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Gets or sets the <see cref="Avalonia.Media.IBrush"/> used to fill the interior of the shape described by this <see cref="GeometryDrawing"/>. /// Gets or sets the <see cref="Avalonia.Media.IBrush"/> used to fill the interior of the shape described by this <see cref="GeometryDrawing"/>.
/// </summary> /// </summary>
public IBrush Brush public IBrush? Brush
{ {
get => GetValue(BrushProperty); get => GetValue(BrushProperty);
set => SetValue(BrushProperty, value); set => SetValue(BrushProperty, value);
@ -52,7 +52,7 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Gets or sets the <see cref="Avalonia.Media.IPen"/> used to stroke this <see cref="GeometryDrawing"/>. /// Gets or sets the <see cref="Avalonia.Media.IPen"/> used to stroke this <see cref="GeometryDrawing"/>.
/// </summary> /// </summary>
public IPen Pen public IPen? Pen
{ {
get => GetValue(PenProperty); get => GetValue(PenProperty);
set => SetValue(PenProperty, value); set => SetValue(PenProperty, value);
@ -68,7 +68,8 @@ namespace Avalonia.Media
public override Rect GetBounds() public override Rect GetBounds()
{ {
return Geometry?.GetRenderBounds(s_boundsPen) ?? Rect.Empty; IPen pen = Pen ?? s_boundsPen;
return Geometry?.GetRenderBounds(pen) ?? Rect.Empty;
} }
} }
} }

58
src/Avalonia.Base/GeometryGroup.cs → src/Avalonia.Base/Media/GeometryGroup.cs

@ -1,7 +1,4 @@
using System; using Avalonia.Metadata;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Metadata;
using Avalonia.Platform; using Avalonia.Platform;
#nullable enable #nullable enable
@ -13,29 +10,36 @@ namespace Avalonia.Media
/// </summary> /// </summary>
public class GeometryGroup : Geometry public class GeometryGroup : Geometry
{ {
public static readonly DirectProperty<GeometryGroup, GeometryCollection?> ChildrenProperty = public static readonly DirectProperty<GeometryGroup, GeometryCollection> ChildrenProperty =
AvaloniaProperty.RegisterDirect<GeometryGroup, GeometryCollection?> ( AvaloniaProperty.RegisterDirect<GeometryGroup, GeometryCollection> (
nameof(Children), nameof(Children),
o => o.Children, o => o.Children,
(o, v) => o.Children = v); (o, v)=> o.Children = v);
public static readonly StyledProperty<FillRule> FillRuleProperty = public static readonly StyledProperty<FillRule> FillRuleProperty =
AvaloniaProperty.Register<GeometryGroup, FillRule>(nameof(FillRule)); AvaloniaProperty.Register<GeometryGroup, FillRule>(nameof(FillRule));
private GeometryCollection? _children; private GeometryCollection _children;
private bool _childrenSet;
public GeometryGroup()
{
_children = new GeometryCollection
{
Parent = this
};
}
/// <summary> /// <summary>
/// Gets or sets the collection that contains the child geometries. /// Gets or sets the collection that contains the child geometries.
/// </summary> /// </summary>
[Content] [Content]
public GeometryCollection? Children public GeometryCollection Children
{ {
get => _children ??= (!_childrenSet ? new GeometryCollection() : null); get => _children;
set set
{ {
SetAndRaise(ChildrenProperty, ref _children, value); OnChildrenChanged(_children, value);
_childrenSet = true; SetAndRaise(ChildrenProperty, ref _children, value);
} }
} }
@ -52,16 +56,28 @@ namespace Avalonia.Media
public override Geometry Clone() public override Geometry Clone()
{ {
var result = new GeometryGroup { FillRule = FillRule, Transform = Transform }; var result = new GeometryGroup { FillRule = FillRule, Transform = Transform };
if (_children?.Count > 0)
if (_children.Count > 0)
{
result.Children = new GeometryCollection(_children); result.Children = new GeometryCollection(_children);
}
return result; return result;
} }
protected void OnChildrenChanged(GeometryCollection oldChildren, GeometryCollection newChildren)
{
oldChildren.Parent = null;
newChildren.Parent = this;
}
protected override IGeometryImpl? CreateDefiningGeometry() protected override IGeometryImpl? CreateDefiningGeometry()
{ {
if (_children?.Count > 0) if (_children.Count > 0)
{ {
var factory = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>(); var factory = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
return factory.CreateGeometryGroup(FillRule, _children); return factory.CreateGeometryGroup(FillRule, _children);
} }
@ -72,10 +88,18 @@ namespace Avalonia.Media
{ {
base.OnPropertyChanged(change); base.OnPropertyChanged(change);
if (change.Property == ChildrenProperty || change.Property == FillRuleProperty) switch (change.Property.Name)
{ {
InvalidateGeometry(); case nameof(FillRule):
case nameof(Children):
InvalidateGeometry();
break;
} }
} }
internal void Invalidate()
{
InvalidateGeometry();
}
} }
} }

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

@ -194,6 +194,19 @@ namespace Avalonia.Media
} }
} }
/// <summary>
/// Obtains geometry for the glyph run.
/// </summary>
/// <returns>The geometry returned contains the combined geometry of all glyphs in the glyph run.</returns>
public Geometry BuildGeometry()
{
var platformRenderInterface = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
var geometryImpl = platformRenderInterface.BuildGlyphRunGeometry(this);
return new PlatformGeometry(geometryImpl);
}
/// <summary> /// <summary>
/// Retrieves the offset from the leading edge of the <see cref="GlyphRun"/> /// Retrieves the offset from the leading edge of the <see cref="GlyphRun"/>
/// to the leading or trailing edge of a caret stop containing the specified character hit. /// to the leading or trailing edge of a caret stop containing the specified character hit.

24
src/Avalonia.Base/Media/PlatformGeometry.cs

@ -0,0 +1,24 @@
using Avalonia.Platform;
namespace Avalonia.Media
{
internal class PlatformGeometry : Geometry
{
private readonly IGeometryImpl _geometryImpl;
public PlatformGeometry(IGeometryImpl geometryImpl)
{
_geometryImpl = geometryImpl;
}
public override Geometry Clone()
{
return new PlatformGeometry(_geometryImpl);
}
protected override IGeometryImpl? CreateDefiningGeometry()
{
return _geometryImpl;
}
}
}

42
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDi.trie.cs

@ -0,0 +1,42 @@
using System;
namespace Avalonia.Media.TextFormatting.Unicode
{
internal static class BiDiTrie
{
public static ReadOnlySpan<byte> Data => new byte[]
{
0,16,0,0,0,0,0,0,0,0,174,224,0,68,12,187,243,236,157,11,176,85,85,25,199,151,115,207,189,247,156,203,227,94,244,132,151,128,58,122,53,184,10,74,112,26,206,61,64,105,130,89,22,163,121,85,12,17,38,26,7,197,72,37,152,166,59,56,142,132,236,64,144,16,196,212,6,26,167,98,34,197,158,71,83,10,134,116,116,236,161,165,4,50,38,61,40,64,137,178,
28,109,6,164,255,102,175,205,93,44,246,99,61,247,62,192,254,102,126,243,173,189,246,218,235,251,214,183,190,253,60,251,156,51,171,129,144,91,193,87,192,157,224,1,176,14,172,7,143,3,7,172,144,208,63,3,191,0,207,130,223,130,109,224,79,224,85,240,23,176,15,188,5,246,131,183,3,182,63,4,26,115,225,253,247,193,186,51,192,96,208,1,206,7,99,64,23,184,24,92,
10,38,131,43,193,117,96,6,152,5,230,128,249,96,30,88,0,22,129,101,224,223,121,66,222,5,7,65,174,64,200,80,212,141,6,99,193,90,44,175,134,94,227,150,115,132,124,15,108,4,143,131,39,192,102,240,28,93,126,17,188,194,44,191,6,118,211,246,251,193,219,116,251,67,57,111,44,141,141,132,20,192,0,112,6,24,12,58,26,123,251,63,191,209,107,127,24,109,47,108,
244,236,249,246,29,212,141,109,244,180,203,4,148,39,49,203,159,68,249,74,186,124,53,244,245,180,252,5,232,91,192,92,112,144,246,227,128,30,44,47,4,75,193,125,76,63,142,65,30,162,253,62,194,245,191,193,176,189,31,115,253,61,133,229,167,192,211,24,239,211,116,204,91,176,252,124,163,231,203,75,92,251,237,88,126,148,137,141,3,118,161,110,15,215,110,31,150,107,200,143,
183,104,253,255,160,79,107,242,202,5,232,211,105,253,155,232,107,64,147,55,239,131,154,188,249,60,139,182,27,78,245,72,170,29,134,49,168,27,23,80,239,80,182,129,223,180,168,197,232,227,232,247,83,96,50,184,6,244,96,28,27,193,13,40,223,8,22,162,188,24,204,199,24,230,96,121,62,184,131,250,114,119,147,55,110,159,217,76,185,22,192,38,112,15,221,118,37,244,55,185,
237,107,224,48,234,182,210,242,90,102,204,223,13,104,91,19,96,67,200,118,47,48,229,223,131,29,133,248,88,241,125,252,153,234,61,224,128,164,95,239,128,67,92,157,19,149,203,77,92,46,55,29,159,3,110,31,141,200,131,45,180,175,124,75,111,223,173,76,185,198,113,38,214,13,5,91,209,231,11,76,191,127,104,234,221,39,55,198,196,229,231,104,187,137,46,239,68,249,175,180,
159,55,160,255,195,249,234,128,119,154,142,221,127,30,51,184,223,59,25,36,139,1,57,101,98,80,19,56,126,56,25,36,139,1,201,98,208,144,197,32,139,1,201,98,208,144,197,32,139,1,201,98,208,144,197,160,94,99,176,179,201,187,174,117,159,9,56,2,237,115,205,189,229,66,179,247,44,205,95,190,150,62,163,217,203,212,13,96,218,59,96,16,150,75,180,110,24,179,110,36,
182,185,144,46,143,133,254,40,45,175,198,115,156,75,104,249,49,250,156,232,114,44,95,213,236,61,183,115,151,175,109,246,158,211,77,231,108,29,224,158,33,221,200,173,119,50,72,22,3,146,197,160,33,139,65,22,3,146,197,160,33,139,65,22,3,146,197,160,225,196,141,193,205,184,198,107,193,53,104,255,130,247,185,178,10,231,182,28,95,247,29,212,141,4,31,1,75,209,247,189,
96,46,103,227,81,172,187,28,117,183,195,135,175,130,187,184,235,205,53,117,240,252,184,212,223,99,6,88,71,203,165,0,182,131,246,86,66,166,128,89,96,61,248,73,107,239,250,255,50,229,18,24,209,134,207,186,193,15,192,223,64,251,0,66,38,130,59,193,19,224,101,80,60,29,109,17,163,85,125,97,31,122,45,88,119,90,60,175,11,182,251,96,159,222,114,55,202,171,192,203,
224,69,216,43,130,182,126,98,253,216,162,27,62,172,203,236,147,180,98,208,157,197,159,100,249,71,82,139,65,119,150,127,36,237,252,187,2,231,128,25,253,78,221,249,143,187,62,88,210,124,236,231,221,43,155,123,223,79,89,207,189,167,229,112,92,197,93,223,60,88,135,207,219,54,98,12,223,134,95,235,221,103,134,205,222,251,97,63,106,238,93,239,62,111,124,146,46,255,146,174,
255,21,244,175,153,54,47,49,101,135,121,87,104,71,115,239,251,131,238,251,104,187,2,218,57,13,158,253,61,204,186,127,161,252,110,72,91,7,28,196,186,92,222,43,187,244,205,123,253,223,79,183,41,230,143,125,239,111,8,179,236,112,156,21,177,206,1,195,177,126,20,215,102,12,181,55,14,250,99,224,19,116,253,228,152,190,156,0,174,102,182,153,134,242,76,174,143,155,176,124,
27,173,155,39,209,255,135,35,222,107,236,65,63,11,21,124,117,100,200,123,122,57,213,78,138,108,166,121,177,138,241,229,225,58,240,203,225,120,30,251,218,79,21,223,169,116,20,120,4,49,216,0,126,200,196,162,70,143,115,19,66,252,168,209,245,155,19,190,119,219,72,245,34,58,151,223,247,215,53,123,250,73,140,97,170,1,159,182,129,45,121,79,63,7,253,59,240,74,130,115,
226,104,242,26,124,221,29,227,239,114,197,220,255,99,29,238,51,14,71,13,57,240,25,238,29,212,207,130,107,90,188,119,78,95,207,247,230,206,110,58,158,197,52,135,28,142,21,1,159,1,214,20,222,7,174,25,96,106,139,119,237,193,214,181,50,227,156,137,242,46,193,207,44,157,147,148,189,121,239,251,19,81,12,44,68,175,255,0,214,159,29,210,230,60,90,63,34,166,143,161,
17,140,118,191,71,81,16,107,91,166,237,198,115,237,251,23,188,239,144,248,223,23,25,26,192,69,220,186,75,4,109,14,213,160,127,193,27,223,104,166,110,52,37,23,98,127,116,4,147,90,226,109,250,251,250,108,170,167,67,207,101,142,127,53,212,213,40,61,45,225,239,232,187,251,210,93,96,9,88,1,86,211,62,106,76,155,26,248,22,237,99,43,152,89,72,63,223,55,193,159,
77,17,108,67,187,109,33,60,19,179,237,166,83,0,66,240,112,54,150,110,128,155,197,35,122,10,45,183,41,210,151,161,155,246,87,161,148,24,42,71,232,36,85,50,156,116,209,229,33,160,200,232,34,104,23,164,200,216,169,112,36,35,211,48,22,2,123,83,143,142,167,66,73,70,22,80,251,61,71,237,183,37,99,184,174,165,45,128,190,33,245,109,22,40,6,228,126,137,214,85,
24,92,241,203,238,118,126,217,109,235,226,231,57,223,214,197,173,231,235,216,126,109,137,237,254,235,221,126,82,34,50,151,65,115,47,130,169,237,101,125,209,177,201,82,62,197,9,139,125,156,196,205,93,84,155,147,81,84,198,42,51,47,39,155,4,29,59,220,243,212,196,58,216,39,202,10,76,228,116,57,164,60,241,36,39,31,66,133,146,163,243,92,162,229,34,213,21,74,89,130,
92,157,83,182,64,94,144,18,83,206,113,62,229,50,8,31,131,184,152,71,229,38,223,71,80,91,191,141,232,253,168,201,57,74,115,206,77,230,254,201,156,183,73,197,33,237,243,131,12,34,177,240,219,250,231,15,31,190,159,160,62,211,20,223,126,144,31,113,99,14,235,75,100,123,25,255,210,138,81,154,115,35,50,31,42,125,232,138,238,124,184,215,3,46,113,109,88,123,166,108,
235,74,84,222,7,249,25,180,63,216,244,69,182,255,176,253,82,116,255,54,33,58,115,26,151,71,108,255,170,199,31,83,194,231,135,175,77,238,207,42,99,59,145,142,173,182,124,229,207,217,62,110,126,185,90,196,151,180,207,227,190,196,229,83,216,190,46,146,59,170,249,101,35,54,97,115,22,54,95,113,146,246,117,134,170,109,209,57,139,186,206,83,149,176,115,94,92,78,197,29,
183,101,175,59,85,69,212,127,157,188,79,235,188,147,132,61,62,167,202,100,92,107,149,84,91,187,200,4,232,241,208,230,237,149,21,8,219,150,173,15,18,19,54,146,68,87,100,198,196,174,227,183,79,66,194,108,217,142,135,74,31,124,127,34,109,117,109,165,33,38,99,31,117,126,23,57,215,171,94,7,152,18,247,125,161,100,228,225,129,85,242,208,64,211,199,90,95,76,206,169,
136,29,222,166,236,62,24,180,191,233,30,59,253,235,21,182,157,104,126,242,207,224,221,119,98,76,73,26,199,219,168,99,174,104,63,42,54,248,253,89,231,90,223,164,36,225,71,208,121,214,166,45,214,102,212,185,159,247,69,117,31,147,221,71,109,156,219,147,190,214,10,242,39,204,47,118,189,106,223,182,198,19,53,71,65,99,50,45,188,141,168,117,54,99,200,183,211,149,160,249,
87,201,81,153,57,143,219,71,131,252,75,83,252,227,174,234,179,31,221,103,70,166,182,119,197,189,94,20,133,125,47,215,149,160,207,29,101,9,123,239,119,4,248,52,56,7,92,20,209,174,157,27,91,123,8,67,40,21,114,71,169,74,22,148,252,235,214,176,246,225,219,47,199,246,203,142,110,175,43,236,92,4,221,99,200,206,179,104,110,70,221,215,132,105,86,68,62,3,9,178,
39,226,135,136,191,81,219,203,32,227,187,168,255,114,156,215,81,37,157,29,252,119,30,76,248,109,90,244,199,26,157,115,21,1,218,13,115,34,141,93,180,63,81,223,121,17,189,94,145,181,159,148,184,126,179,223,151,58,222,167,194,168,42,201,143,234,34,125,160,91,160,251,65,247,133,110,133,238,15,61,0,186,13,154,208,109,223,135,229,34,150,207,132,30,8,61,8,186,29,122,
48,244,251,153,118,68,58,6,101,14,95,226,230,48,106,93,82,241,247,125,182,97,211,70,254,219,20,27,182,147,28,127,146,241,211,57,86,37,57,183,182,108,242,251,188,219,63,95,23,134,168,63,73,30,3,162,150,195,234,76,217,246,251,230,115,68,214,166,200,123,97,58,34,155,195,162,249,16,135,138,68,109,103,195,158,136,63,54,199,43,98,63,204,23,190,94,182,223,168,49,
152,176,225,111,103,162,141,138,77,217,88,233,140,209,244,56,121,159,117,250,178,33,236,59,221,201,157,23,39,28,246,190,31,63,238,112,58,223,207,159,70,237,79,165,246,103,96,121,58,45,207,68,249,243,199,248,149,164,164,121,223,163,123,141,88,175,215,216,73,29,227,69,236,154,56,231,156,8,247,53,186,231,184,176,24,165,113,238,246,237,218,236,219,212,184,162,226,110,82,162,
108,196,249,28,118,30,76,99,94,227,108,199,181,211,181,231,47,219,20,27,253,71,197,43,106,126,249,114,26,34,58,135,105,251,108,211,166,232,254,166,154,163,65,219,201,230,76,84,223,34,231,5,155,34,122,204,78,43,215,69,246,199,164,37,42,199,194,252,17,201,207,36,198,34,234,135,168,63,162,62,203,216,21,21,145,220,77,34,151,69,237,217,222,175,85,226,33,114,92,11,
138,91,82,49,228,219,132,249,97,226,120,172,42,113,190,218,144,184,123,35,255,25,174,143,238,189,150,201,251,45,219,251,130,72,174,155,234,91,71,252,152,166,113,14,243,69,118,44,113,191,77,104,234,88,99,67,146,176,35,179,159,152,122,95,67,245,184,47,115,110,240,197,84,63,65,253,138,74,146,57,162,98,203,100,158,185,199,110,153,92,176,121,220,78,251,51,104,94,252,99,
78,82,191,53,19,246,251,51,124,125,84,187,52,126,39,135,95,167,251,187,68,38,252,115,223,27,181,53,246,122,24,159,42,238,254,20,149,79,162,121,154,86,110,197,249,152,100,28,195,16,253,189,60,27,168,198,218,214,252,37,145,59,174,4,221,151,120,117,5,124,78,153,63,250,57,229,16,250,251,143,67,168,46,74,156,251,138,33,243,93,150,232,163,221,0,188,152,232,211,164,
63,178,162,107,199,196,189,167,159,27,58,247,178,238,246,46,252,181,11,155,151,65,215,51,186,231,147,56,191,252,255,71,24,14,46,3,227,193,40,112,5,205,233,82,0,21,9,74,41,83,214,164,162,73,145,209,174,176,117,30,159,123,175,74,174,123,175,139,92,15,61,21,250,6,232,105,208,36,52,230,37,138,223,95,24,174,136,252,166,127,208,182,252,61,181,123,254,208,141,165,
10,113,191,75,25,151,255,162,231,70,209,253,167,72,46,45,85,201,164,35,223,55,170,88,102,74,2,54,42,145,20,58,112,126,196,119,97,250,64,183,72,127,39,166,34,137,13,137,182,121,211,176,42,153,53,172,139,204,134,190,25,250,139,208,183,64,127,9,122,14,244,109,208,183,66,207,133,190,29,122,30,244,151,161,137,196,184,158,197,54,207,72,110,67,52,249,7,108,254,29,
54,247,66,239,129,126,3,122,31,244,126,232,55,161,15,64,255,211,176,79,95,235,172,146,133,157,93,228,110,232,69,208,14,244,98,232,37,208,95,135,190,7,122,41,244,10,232,123,161,151,67,47,131,94,9,253,13,232,85,208,247,65,223,15,189,26,250,1,232,53,157,102,125,140,99,7,108,110,135,205,157,208,175,38,108,155,128,67,176,123,208,170,93,95,108,143,69,206,70,199,
5,85,114,246,5,93,228,92,232,115,160,135,65,127,8,186,19,122,56,52,73,120,30,236,197,72,86,108,231,129,174,232,218,77,235,247,173,125,127,116,255,15,73,213,182,202,239,108,235,92,159,134,137,191,158,239,51,41,49,53,143,182,238,143,226,226,104,99,159,172,199,227,150,234,113,36,109,31,146,242,223,244,248,249,237,85,37,169,248,155,154,195,184,216,198,197,92,103,174,77,
140,67,39,31,85,164,30,198,171,147,7,186,199,255,52,206,223,166,8,242,39,105,177,241,31,145,50,232,94,255,164,109,95,20,87,100,234,101,250,213,17,21,159,85,125,20,181,21,214,214,190,252,31,0,0,255,255,0,0,0,255,255,99,102,0,0};
}
}

31
src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.trie.cs

@ -0,0 +1,31 @@
using System;
namespace Avalonia.Media.TextFormatting.Unicode
{
internal static class GraphemeBreakTrie
{
public static ReadOnlySpan<byte> Data => new byte[]
{
0,14,16,0,0,0,0,0,0,0,133,64,0,245,7,10,248,236,157,127,136,29,87,21,199,103,157,111,246,157,100,211,138,180,69,177,5,241,7,88,91,40,182,150,210,12,138,161,88,27,163,96,241,15,75,161,210,18,44,149,10,193,46,24,80,49,254,163,33,16,136,54,127,84,8,34,18,253,199,68,196,42,136,154,82,21,149,6,218,82,43,72,107,161,54,22,196,173,10,110,
16,140,210,82,250,125,190,51,228,228,228,206,204,157,121,119,230,109,182,243,133,15,231,220,115,207,156,123,239,121,111,247,253,216,129,189,33,207,178,130,220,66,118,147,61,228,126,19,43,230,180,171,228,139,100,31,217,31,145,127,128,28,174,153,63,66,142,146,99,228,56,249,49,249,5,249,21,57,101,242,158,36,127,36,207,145,23,201,26,89,39,255,34,103,201,43,4,200,178,47,
147,175,146,131,152,93,91,242,40,217,206,216,55,200,17,114,148,28,35,199,201,9,242,19,114,146,252,134,252,150,60,65,158,54,227,63,145,191,104,254,75,228,140,94,255,63,242,32,89,218,50,91,103,43,237,25,218,55,109,57,87,255,205,244,223,166,227,119,211,190,135,92,110,214,47,152,127,61,99,103,39,51,127,7,253,157,90,175,32,31,162,255,49,29,223,78,123,135,250,119,
211,222,71,246,146,255,154,243,238,227,120,63,57,64,14,155,58,5,185,82,206,241,46,229,26,242,126,165,48,185,69,13,95,143,204,43,18,243,16,207,243,16,121,158,231,125,94,207,252,45,142,191,87,246,7,231,231,95,193,248,247,93,15,30,118,227,194,240,51,157,251,37,237,99,234,239,37,47,235,252,83,140,253,129,60,71,78,147,53,178,174,121,103,213,190,26,168,143,101,62,
255,150,47,140,151,172,146,203,107,230,139,72,62,201,243,223,165,61,184,201,196,247,146,7,106,206,93,140,100,125,247,224,42,247,248,158,12,60,7,138,4,252,213,252,12,188,61,193,115,170,24,201,198,30,100,99,15,242,177,7,99,15,178,177,7,249,216,131,177,7,217,216,131,124,236,193,216,131,108,236,65,62,246,96,236,65,150,188,7,87,47,207,190,75,43,199,159,136,248,254,
226,189,188,230,102,243,153,247,24,191,83,123,133,236,100,108,151,198,111,167,189,131,92,37,179,239,3,239,162,15,250,159,214,249,251,105,87,201,62,29,239,167,253,51,237,129,134,207,210,135,57,127,43,235,124,152,220,70,118,145,143,144,221,228,163,228,214,113,46,27,251,146,141,207,9,25,127,30,198,223,5,89,178,223,5,55,144,29,228,3,164,24,223,139,100,99,15,178,177,7,
249,216,131,62,122,112,164,231,191,167,236,87,138,0,187,3,177,51,198,191,199,253,237,179,88,0,187,46,153,113,144,172,109,111,230,20,243,158,13,228,190,229,210,243,199,187,56,62,72,78,145,236,141,179,216,141,180,159,33,223,33,143,144,117,178,115,37,203,62,71,94,220,202,191,125,109,203,50,89,154,113,167,241,197,113,98,229,194,88,136,47,153,26,63,162,255,15,94,119,45,
247,113,47,57,176,61,174,198,72,54,246,96,105,236,193,216,131,108,236,193,210,230,235,193,58,95,23,50,190,46,60,202,247,9,167,249,122,248,146,222,231,177,198,239,174,222,202,215,231,119,232,107,244,223,201,239,152,179,194,207,44,143,47,207,230,127,79,123,141,121,13,127,54,240,94,227,36,57,189,124,238,62,178,53,250,235,21,239,73,254,195,248,171,102,110,153,223,131,93,170,
247,152,21,1,46,227,220,149,102,254,157,147,115,247,61,77,185,118,114,254,253,95,239,171,169,117,115,205,92,65,174,227,57,111,114,239,87,62,200,107,110,35,31,159,94,11,222,203,164,53,110,113,121,69,4,159,50,235,223,75,255,179,110,63,15,112,188,91,235,126,161,97,175,133,225,43,45,114,139,30,185,175,67,79,138,158,249,46,123,179,99,192,245,246,178,7,39,184,230,195,
129,199,228,231,27,228,113,42,90,178,71,239,3,91,85,246,56,86,107,248,60,46,204,127,189,81,204,193,209,134,207,118,47,187,241,177,13,120,111,221,113,238,233,135,21,251,186,34,209,253,159,63,104,121,238,159,6,242,207,246,220,135,175,233,207,255,161,13,240,123,224,65,238,225,50,190,206,127,211,236,229,219,9,246,181,74,126,61,153,217,83,180,79,145,103,54,192,121,139,72,
94,224,94,255,214,176,223,67,29,207,243,207,139,160,15,135,220,30,255,125,17,236,185,232,192,35,27,96,15,215,231,75,255,39,231,219,243,60,130,55,24,127,41,242,154,60,130,81,139,211,216,255,44,217,243,56,239,200,162,31,55,188,206,73,41,212,176,153,133,139,144,114,223,165,197,212,9,248,155,93,147,10,98,133,22,164,254,221,149,90,232,129,20,123,26,66,168,97,210,144,
227,107,100,53,57,41,53,81,139,148,69,91,10,9,217,204,66,11,46,86,33,130,216,58,214,135,62,215,177,0,36,16,203,52,46,138,31,195,252,108,214,9,117,147,145,18,3,28,226,226,165,38,165,211,81,147,142,215,133,36,166,230,36,148,16,56,87,121,29,166,206,156,130,214,18,199,84,162,216,92,104,12,186,95,49,22,101,226,130,132,10,68,247,8,71,72,147,10,208,1,
49,126,149,80,193,68,237,144,130,33,239,161,126,174,181,183,168,159,39,170,153,87,144,66,121,75,134,88,175,73,112,207,61,184,121,113,115,80,242,6,144,128,124,78,250,18,28,161,24,166,193,134,49,76,124,40,193,80,55,39,126,114,64,65,215,135,142,197,128,6,36,144,47,74,89,27,21,196,10,202,34,4,119,158,161,215,246,123,128,163,148,40,126,140,50,208,32,52,204,251,
92,216,64,207,130,243,225,206,58,148,224,122,43,26,67,69,46,2,99,84,212,76,181,63,4,98,177,18,205,135,99,42,40,50,29,168,21,141,165,22,148,190,132,10,134,22,140,133,233,39,12,165,68,241,99,148,129,10,193,16,43,196,38,38,22,2,231,204,76,76,166,3,55,6,137,17,34,115,196,128,152,194,9,5,183,190,152,56,20,63,198,52,80,35,40,139,16,212,138,250,
18,240,203,60,81,166,18,5,74,157,160,196,8,138,40,139,20,148,210,151,169,19,41,84,196,68,129,193,230,75,13,208,156,121,5,181,162,62,42,136,169,131,26,82,9,145,251,133,201,109,83,27,1,134,18,148,190,215,8,89,43,81,82,158,9,45,145,138,184,173,25,18,90,208,54,31,61,48,175,16,217,55,184,124,113,185,125,74,26,214,66,205,92,91,193,209,69,80,43,234,
35,34,183,171,208,245,194,134,154,80,250,20,20,49,62,2,72,3,112,62,34,137,221,99,95,130,65,28,8,196,189,68,129,241,197,1,67,159,130,34,10,122,90,71,204,58,168,161,220,147,181,165,143,26,164,2,68,82,10,1,164,156,28,72,168,65,140,21,7,140,191,40,33,130,174,53,165,237,133,9,37,129,115,136,139,139,155,79,45,184,53,196,0,55,7,51,215,86,210,0,
26,16,151,55,175,96,240,99,68,34,13,243,94,240,129,138,57,209,49,76,204,11,3,81,181,214,60,130,97,72,65,73,85,7,74,40,134,10,188,208,48,174,138,165,148,40,80,36,144,131,158,214,20,183,246,80,66,34,186,174,93,55,135,26,250,16,90,32,74,234,245,69,129,67,92,92,148,170,58,67,10,21,136,130,138,113,151,117,98,114,164,41,169,71,161,167,122,48,216,57,
148,3,39,40,109,36,230,58,81,234,242,218,74,20,84,248,153,137,45,90,216,228,107,35,64,76,174,29,135,4,71,223,130,33,52,215,70,80,82,74,180,166,164,44,218,81,8,32,21,113,24,250,18,18,215,19,3,34,144,132,107,136,137,137,137,87,9,106,197,128,6,250,16,220,30,196,204,73,197,88,90,212,142,149,40,246,90,84,96,133,0,125,75,12,104,64,2,121,162,182,
79,33,97,29,81,80,129,4,242,36,48,143,68,123,234,42,232,94,68,125,24,74,137,3,138,24,127,72,65,73,37,49,160,1,49,121,162,182,141,96,174,19,227,35,128,168,109,146,40,112,72,32,134,166,98,29,36,6,68,32,198,79,37,49,192,81,10,138,56,80,38,168,68,237,144,66,36,67,236,35,54,15,1,68,129,97,30,137,171,5,199,84,168,64,212,166,18,58,146,153,
189,160,2,169,240,83,9,21,248,156,210,98,234,24,27,35,9,80,214,192,212,49,113,24,155,82,80,68,73,89,19,134,148,66,13,41,106,103,166,31,210,129,58,193,209,69,104,153,47,202,34,5,197,250,152,14,84,168,161,47,193,209,103,253,33,133,30,73,181,86,147,208,148,208,49,183,173,16,160,42,142,72,230,21,106,104,154,71,36,165,80,131,157,207,106,114,82,11,142,212,
245,96,232,83,162,244,85,87,90,176,104,137,50,228,90,178,32,182,110,0,172,182,45,152,149,158,185,196,209,86,219,18,226,181,178,1,240,226,191,181,184,160,103,125,50,244,122,94,175,1,0,0,255,255,0,0,0,255,255,99,102,0,0};
}
}

39
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.cs

@ -1,4 +1,5 @@
using System.Runtime.CompilerServices; using System.IO;
using System.Runtime.CompilerServices;
namespace Avalonia.Media.TextFormatting.Unicode namespace Avalonia.Media.TextFormatting.Unicode
{ {
@ -17,14 +18,14 @@ namespace Avalonia.Media.TextFormatting.Unicode
internal const int SCRIPT_SHIFT = CATEGORY_BITS; internal const int SCRIPT_SHIFT = CATEGORY_BITS;
internal const int LINEBREAK_SHIFT = CATEGORY_BITS + SCRIPT_BITS; internal const int LINEBREAK_SHIFT = CATEGORY_BITS + SCRIPT_BITS;
internal const int BIDIPAIREDBRACKEDTYPE_SHIFT = BIDIPAIREDBRACKED_BITS; internal const int BIDIPAIREDBRACKEDTYPE_SHIFT = BIDIPAIREDBRACKED_BITS;
internal const int BIDICLASS_SHIFT = BIDIPAIREDBRACKED_BITS + BIDIPAIREDBRACKEDTYPE_BITS; internal const int BIDICLASS_SHIFT = BIDIPAIREDBRACKED_BITS + BIDIPAIREDBRACKEDTYPE_BITS;
internal const int CATEGORY_MASK = (1 << CATEGORY_BITS) - 1; internal const int CATEGORY_MASK = (1 << CATEGORY_BITS) - 1;
internal const int SCRIPT_MASK = (1 << SCRIPT_BITS) - 1; internal const int SCRIPT_MASK = (1 << SCRIPT_BITS) - 1;
internal const int LINEBREAK_MASK = (1 << LINEBREAK_BITS) - 1; internal const int LINEBREAK_MASK = (1 << LINEBREAK_BITS) - 1;
internal const int BIDIPAIREDBRACKED_MASK = (1 << BIDIPAIREDBRACKED_BITS) - 1; internal const int BIDIPAIREDBRACKED_MASK = (1 << BIDIPAIREDBRACKED_BITS) - 1;
internal const int BIDIPAIREDBRACKEDTYPE_MASK = (1 << BIDIPAIREDBRACKEDTYPE_BITS) - 1; internal const int BIDIPAIREDBRACKEDTYPE_MASK = (1 << BIDIPAIREDBRACKEDTYPE_BITS) - 1;
internal const int BIDICLASS_MASK = (1 << BIDICLASS_BITS) - 1; internal const int BIDICLASS_MASK = (1 << BIDICLASS_BITS) - 1;
@ -35,9 +36,29 @@ namespace Avalonia.Media.TextFormatting.Unicode
static UnicodeData() static UnicodeData()
{ {
s_unicodeDataTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.UnicodeData.trie")!); unsafe
s_graphemeBreakTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.GraphemeBreak.trie")!); {
s_biDiTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.BiDi.trie")!); var unicodeData = UnicodeDataTrie.Data;
fixed (byte* unicodeDataPtr = unicodeData)
{
s_unicodeDataTrie = new UnicodeTrie(new UnmanagedMemoryStream(unicodeDataPtr, unicodeData.Length));
}
var graphemeData = GraphemeBreakTrie.Data;
fixed (byte* graphemeDataPtr = graphemeData)
{
s_graphemeBreakTrie = new UnicodeTrie(new UnmanagedMemoryStream(graphemeDataPtr, graphemeData.Length));
}
var bidiData = BiDiTrie.Data;
fixed (byte* bidiDataPtr = bidiData)
{
s_biDiTrie = new UnicodeTrie(new UnmanagedMemoryStream(bidiDataPtr, bidiData.Length));
}
}
} }
/// <summary> /// <summary>
@ -72,7 +93,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
{ {
return (BidiClass)((s_biDiTrie.Get(codepoint) >> BIDICLASS_SHIFT) & BIDICLASS_MASK); return (BidiClass)((s_biDiTrie.Get(codepoint) >> BIDICLASS_SHIFT) & BIDICLASS_MASK);
} }
/// <summary> /// <summary>
/// Gets the <see cref="BidiPairedBracketType"/> for a Unicode codepoint. /// Gets the <see cref="BidiPairedBracketType"/> for a Unicode codepoint.
/// </summary> /// </summary>
@ -83,7 +104,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
{ {
return (BidiPairedBracketType)((s_biDiTrie.Get(codepoint) >> BIDIPAIREDBRACKEDTYPE_SHIFT) & BIDIPAIREDBRACKEDTYPE_MASK); return (BidiPairedBracketType)((s_biDiTrie.Get(codepoint) >> BIDIPAIREDBRACKEDTYPE_SHIFT) & BIDIPAIREDBRACKEDTYPE_MASK);
} }
/// <summary> /// <summary>
/// Gets the paired bracket for a Unicode codepoint. /// Gets the paired bracket for a Unicode codepoint.
/// </summary> /// </summary>

122
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.trie.cs

@ -0,0 +1,122 @@
using System;
namespace Avalonia.Media.TextFormatting.Unicode
{
internal static class UnicodeDataTrie
{
public static ReadOnlySpan<byte> Data => new byte[]
{
0,16,0,0,0,0,0,0,0,1,154,144,0,161,43,94,212,236,157,15,148,28,85,157,239,107,230,215,147,204,84,146,78,103,152,252,115,128,16,8,241,224,234,238,193,197,221,163,139,231,117,2,132,158,162,51,52,67,155,63,244,152,233,66,130,202,81,247,225,209,221,167,7,125,13,139,74,202,48,84,134,89,16,199,5,70,81,244,249,111,117,209,93,93,229,5,68,157,41,218,
177,9,35,168,3,72,16,124,60,149,125,111,87,217,231,62,193,247,190,53,117,59,115,231,166,254,220,234,170,234,10,58,57,231,147,223,253,255,251,221,63,117,235,214,173,59,213,151,100,20,101,47,208,193,91,193,181,224,0,56,4,110,3,147,224,51,224,139,224,31,193,127,7,223,5,223,7,143,130,199,193,51,224,57,240,60,248,13,80,186,20,165,27,228,192,6,112,26,56,19,
188,10,188,6,188,30,108,7,26,24,2,151,129,125,224,74,240,14,240,87,224,253,224,131,224,58,96,128,155,192,173,224,239,192,39,193,231,193,87,192,55,193,183,193,247,192,15,192,143,193,83,224,25,240,28,120,30,188,8,104,153,162,172,0,39,129,126,112,6,248,35,240,185,94,69,249,83,200,191,0,231,129,29,96,16,148,193,59,215,41,202,217,39,33,30,252,5,184,7,105,
135,17,126,57,184,202,142,95,166,40,239,5,53,112,3,48,193,71,192,237,224,83,224,11,224,171,224,27,224,1,80,7,179,224,49,240,52,248,5,248,21,248,15,208,177,92,81,122,192,26,176,30,108,2,47,7,127,2,206,131,238,63,135,252,79,224,66,48,8,118,129,125,224,74,112,21,120,231,114,199,246,247,66,94,11,14,48,255,69,200,251,94,212,227,16,252,183,128,219,193,
39,193,231,89,252,165,136,223,11,116,240,86,112,53,184,100,13,218,22,241,23,160,190,239,129,255,61,140,107,25,31,2,7,24,135,24,223,92,238,200,111,67,78,131,135,152,255,81,38,31,135,124,6,60,7,246,162,252,189,224,121,184,111,67,220,71,99,226,14,240,34,202,188,27,242,110,208,213,173,40,171,192,90,112,10,56,19,124,17,225,95,6,175,130,251,53,224,245,224,235,
240,127,3,117,189,0,238,251,224,222,217,237,148,119,9,228,94,160,131,183,130,119,128,105,132,255,21,228,53,96,207,6,69,185,30,242,33,132,29,132,28,7,31,3,119,129,207,117,59,237,251,35,196,61,102,143,157,110,232,0,79,195,253,75,240,107,240,0,252,47,64,214,33,103,193,3,176,225,49,200,39,193,179,224,127,131,127,197,245,180,19,225,117,240,6,123,252,245,34,109,
175,115,93,253,166,219,185,62,121,244,53,139,253,74,15,108,71,88,6,114,37,184,2,121,251,32,79,6,91,192,107,215,43,202,54,48,0,94,9,255,57,160,128,122,157,11,121,62,184,26,121,223,3,174,5,22,198,81,17,97,159,66,218,207,130,47,129,175,129,251,192,52,120,8,252,8,60,9,158,5,207,129,171,193,123,64,21,101,62,15,249,34,200,192,221,3,214,108,112,194,
47,69,153,21,240,12,202,255,25,120,11,194,222,2,158,227,220,111,7,87,131,247,128,141,96,51,56,11,92,11,14,128,67,224,108,48,6,62,10,62,14,254,27,248,50,211,241,85,91,255,58,69,249,237,58,199,127,45,236,184,1,220,11,247,189,62,60,203,234,242,44,195,100,242,86,112,187,16,247,172,11,85,148,241,90,144,7,111,178,251,162,199,9,107,114,0,237,122,53,194,
222,13,14,193,125,27,199,251,16,246,54,244,215,7,32,51,125,138,242,97,200,155,193,4,227,58,212,229,173,208,241,24,210,124,162,199,25,111,159,133,252,14,202,253,142,93,247,158,5,183,200,215,17,119,24,60,141,188,191,4,83,112,175,132,142,6,100,31,228,201,224,215,8,255,33,252,143,129,45,240,111,1,71,225,126,37,228,140,221,54,61,24,163,128,96,67,15,120,100,131,
227,94,3,158,128,251,41,240,115,198,47,55,56,121,68,206,65,89,231,44,161,44,181,129,178,212,6,125,242,109,208,156,63,206,9,145,231,156,37,148,165,54,80,150,218,160,111,169,13,150,218,64,89,106,131,190,165,54,88,106,3,101,169,13,250,254,48,219,224,55,120,118,123,1,207,120,231,194,125,238,9,130,162,226,185,19,235,218,229,144,25,236,141,156,143,176,243,125,88,137,
52,171,85,103,239,112,18,207,204,159,1,69,132,23,193,122,132,247,33,254,75,108,79,228,171,144,247,130,7,192,38,196,157,14,202,72,247,10,200,97,200,87,67,94,1,249,102,240,58,184,255,18,242,175,193,251,193,118,248,53,240,65,184,13,48,4,247,101,96,12,238,203,33,175,2,39,219,251,80,125,216,23,0,239,132,255,189,224,58,96,128,119,161,157,15,65,94,3,121,13,
248,20,210,220,6,255,23,32,191,8,254,30,124,9,124,25,252,3,184,7,124,97,41,78,89,106,23,101,105,76,244,45,93,15,75,115,129,18,219,92,48,137,121,247,211,224,179,224,106,220,23,174,78,17,29,123,165,122,138,236,93,66,89,106,3,101,169,13,214,187,183,65,152,245,244,63,168,11,238,127,132,251,94,240,29,48,3,30,81,157,247,212,54,223,64,252,19,156,255,219,
1,60,128,244,218,50,199,253,83,150,239,127,66,62,7,158,183,215,151,235,240,94,13,178,107,197,226,124,43,224,63,9,212,177,222,189,30,107,206,45,88,159,158,5,250,17,118,6,248,163,21,233,206,61,54,15,176,245,120,6,246,157,223,235,216,105,191,139,125,193,126,46,57,9,235,102,112,15,120,18,156,134,118,168,130,113,48,11,186,215,226,93,37,248,47,224,159,192,111,64,
55,218,226,92,240,46,112,15,248,53,56,7,122,222,2,198,193,44,88,137,231,139,34,56,104,239,161,171,138,114,39,120,18,156,134,246,168,130,15,131,7,153,124,142,201,15,115,188,106,37,222,215,195,230,14,240,118,184,63,191,114,113,188,205,115,8,91,181,106,193,191,19,238,27,193,247,192,170,44,252,224,70,112,103,71,188,124,143,149,217,181,26,239,179,87,59,238,18,147,119,
50,62,8,255,167,192,207,184,240,173,57,39,172,157,108,203,29,223,110,75,40,75,109,176,98,169,13,150,218,64,249,131,104,131,107,83,158,3,21,156,151,82,82,226,190,92,186,207,94,39,2,127,138,62,120,29,216,190,194,57,191,83,199,186,166,206,208,16,54,4,222,0,142,96,29,243,3,240,70,184,247,131,17,236,221,190,157,229,217,193,241,238,21,206,218,232,125,144,31,0,
143,193,125,35,228,223,130,219,192,36,120,26,97,159,97,121,103,177,134,249,49,56,104,159,3,234,195,115,50,194,191,6,190,9,190,5,126,221,231,172,133,94,128,60,226,162,47,131,53,87,38,128,31,35,223,83,224,231,46,249,255,13,97,207,131,23,193,74,164,237,178,215,77,43,157,184,181,144,167,128,51,153,127,7,232,91,235,172,191,94,3,54,98,45,247,122,200,243,65,17,
156,140,184,45,107,157,116,175,132,44,35,236,28,200,97,200,43,192,219,192,187,192,53,92,121,231,34,254,92,112,61,11,123,202,110,139,149,88,43,162,61,198,33,207,71,220,199,184,244,59,124,184,11,233,138,72,255,57,46,125,25,254,123,224,255,103,46,236,126,184,167,193,67,96,24,241,251,192,143,224,126,18,92,9,247,85,224,89,184,255,5,188,19,238,127,135,252,29,232,196,
218,241,189,240,191,31,124,16,168,240,247,130,245,171,22,202,222,4,247,203,193,40,226,255,4,242,207,193,235,193,5,171,156,53,168,104,243,45,72,119,27,120,3,226,222,8,38,225,254,36,216,239,146,118,7,248,60,226,222,142,184,119,179,248,175,192,255,53,240,62,248,63,0,238,91,235,172,115,255,150,197,255,29,228,39,61,202,218,1,166,145,254,243,66,252,207,209,7,31,67,
251,127,5,225,223,4,223,2,15,114,105,30,134,251,81,240,19,240,16,242,255,0,252,15,184,31,135,252,41,248,95,112,255,2,242,255,248,232,221,193,248,127,72,147,193,154,121,37,56,9,108,0,167,102,23,226,183,194,253,10,240,106,240,58,144,7,5,46,126,135,15,37,143,116,187,17,190,25,99,119,4,242,87,176,243,87,109,228,205,130,77,143,99,78,121,156,241,151,62,246,
252,181,100,157,119,252,30,243,91,180,195,111,99,224,69,38,187,214,121,167,177,159,99,127,235,18,254,95,79,128,126,200,193,182,92,11,172,21,252,31,106,177,46,69,220,139,138,17,185,9,186,111,5,119,112,54,124,2,238,79,131,83,96,219,102,240,247,112,255,19,56,156,80,155,255,27,230,185,187,236,179,183,217,197,225,103,65,247,89,160,129,240,175,67,62,194,197,63,1,247,
217,8,59,251,15,148,159,181,161,254,175,109,145,127,97,253,244,239,66,127,238,136,153,109,208,181,221,135,223,49,253,203,176,199,178,10,104,8,211,36,89,179,58,126,123,227,102,8,118,14,49,54,194,222,83,193,214,54,218,93,229,206,239,87,5,254,120,181,35,255,140,201,49,216,248,81,112,231,58,199,127,46,194,95,128,124,1,156,239,98,115,145,229,171,130,50,220,195,46,105,
254,175,189,247,216,139,53,237,106,103,223,244,109,144,239,2,215,128,223,217,123,189,171,177,134,5,227,128,16,191,162,119,33,207,139,108,175,117,37,248,45,220,157,189,78,158,9,164,237,131,251,100,112,6,120,5,88,15,54,129,173,224,85,224,19,72,115,63,234,145,217,24,141,79,163,140,207,174,115,228,151,109,247,106,236,157,175,78,127,92,201,242,207,176,245,91,62,246,94,134,
58,61,136,248,135,67,214,233,114,228,155,123,9,180,195,85,176,243,42,23,126,202,108,127,13,198,202,235,193,47,218,80,151,95,65,199,89,88,75,255,134,211,165,96,95,161,43,231,157,103,21,226,214,130,83,192,153,224,85,224,53,44,253,185,62,249,118,48,102,236,107,55,183,240,55,44,5,184,75,160,12,246,130,179,237,119,12,27,157,191,91,234,101,82,207,57,239,131,222,2,
249,159,193,187,192,53,224,122,22,126,47,199,140,240,55,50,47,67,25,167,131,87,128,18,23,254,106,248,95,11,182,129,129,141,11,225,151,192,189,7,236,3,186,173,127,163,19,254,14,200,119,51,247,12,184,6,238,26,243,223,0,121,16,182,140,231,156,185,167,201,199,56,255,93,112,127,14,220,195,194,190,206,228,253,144,223,229,234,97,162,172,143,176,114,191,207,218,233,78,248,
31,97,238,42,87,246,19,224,103,224,151,224,95,89,25,85,97,78,253,15,166,167,210,227,188,115,225,219,234,222,54,211,179,38,253,115,123,73,177,134,181,237,57,39,128,45,231,36,204,198,53,254,237,144,180,254,115,78,96,54,167,92,255,179,82,190,198,239,61,1,56,39,166,107,249,222,151,32,61,109,28,127,103,191,132,219,233,222,152,218,250,181,224,18,172,89,46,97,236,16,
214,59,27,216,119,28,54,184,176,109,205,241,233,95,106,236,245,56,251,179,247,15,128,129,53,233,239,233,164,77,41,211,113,140,109,249,46,9,50,202,182,90,143,178,237,112,183,67,30,110,169,124,93,129,236,175,169,74,165,214,161,84,14,99,189,171,144,178,47,223,9,63,128,187,130,176,97,60,222,236,169,57,113,85,59,78,233,84,118,43,153,121,89,57,220,161,12,29,238,148,
162,98,167,87,58,149,170,93,142,226,48,175,87,33,156,23,107,15,118,93,42,168,195,30,212,103,4,122,119,129,17,48,133,184,169,54,48,12,253,85,244,229,158,60,36,244,110,67,251,255,161,255,219,230,54,46,15,199,55,190,131,216,175,216,99,16,207,174,24,243,251,48,54,246,49,116,244,79,165,214,173,140,0,29,110,235,80,183,114,217,97,167,223,182,163,15,117,54,118,116,
228,171,34,125,25,233,202,243,233,51,74,129,229,173,176,252,101,96,33,255,94,228,47,51,127,217,142,87,236,179,146,201,141,247,42,116,212,125,226,167,18,166,10,253,83,1,105,234,191,231,114,42,166,52,245,19,88,214,125,234,53,229,147,166,46,184,235,46,121,234,33,242,76,5,164,159,10,136,155,146,212,85,119,73,51,5,44,23,123,44,129,58,120,144,203,255,160,135,123,42,
130,156,138,177,127,167,124,108,171,199,168,167,126,130,200,41,15,234,62,253,94,119,105,147,122,68,125,83,47,17,172,54,235,155,150,96,0,247,223,129,0,70,4,6,108,106,221,32,195,100,247,98,191,194,165,113,201,63,210,164,230,220,243,143,161,176,176,121,153,113,181,119,196,142,83,22,179,41,227,208,212,53,32,196,143,180,136,137,53,143,185,132,50,223,6,74,135,35,243,33,
176,243,40,30,132,41,39,239,80,92,65,74,1,20,153,28,176,251,105,197,130,159,176,70,36,48,192,252,5,70,5,207,82,69,46,158,24,35,43,156,126,182,227,42,76,22,25,132,248,34,39,139,172,172,98,12,16,87,102,209,135,66,130,20,5,119,209,69,103,81,82,214,151,97,190,1,245,144,178,224,161,175,234,210,222,5,183,246,95,254,210,166,144,50,197,19,68,234,160,116,
97,215,60,38,187,214,75,112,95,204,40,158,32,118,22,19,144,197,22,243,22,78,16,251,11,17,36,97,30,92,217,73,109,129,216,156,223,3,119,191,7,221,39,0,253,157,157,202,250,237,153,99,246,110,70,216,102,112,234,246,206,121,127,110,103,215,75,142,245,59,51,243,178,127,21,29,11,235,231,221,55,118,204,75,18,238,207,36,160,238,164,182,65,1,186,251,97,127,255,170,
227,211,249,113,93,7,29,199,118,196,220,9,121,39,99,226,218,206,121,110,7,21,172,91,38,58,58,149,73,132,79,2,115,27,230,70,73,42,216,47,190,14,146,160,119,226,90,236,219,193,111,160,12,35,69,6,20,249,180,205,251,128,41,195,54,57,198,238,235,148,98,194,238,131,251,24,130,77,70,202,109,104,156,64,76,96,92,25,1,227,114,187,226,63,118,15,32,238,0,23,
63,233,146,214,96,250,198,208,31,99,18,24,156,141,147,12,195,182,119,115,107,216,215,208,117,144,6,48,117,216,195,220,70,155,49,161,219,140,9,98,115,146,193,235,232,120,105,163,109,57,49,41,93,129,245,172,36,26,210,83,136,123,10,113,28,249,97,167,20,214,6,236,69,165,76,99,79,87,32,211,72,55,13,142,130,185,121,58,149,185,143,116,204,135,17,171,115,3,233,158,
216,211,57,79,227,141,200,199,49,125,10,244,248,248,27,12,98,101,205,33,126,174,69,8,249,181,62,244,119,194,148,202,24,39,12,98,118,87,16,78,226,181,188,217,31,59,61,165,140,145,192,28,64,33,202,165,16,182,154,146,107,12,147,191,111,17,230,236,243,186,148,81,6,217,182,17,116,251,64,205,182,33,119,127,88,40,32,47,177,120,226,251,133,220,109,178,235,98,192,63,
202,213,201,20,32,150,118,148,171,51,113,126,147,149,65,1,237,61,202,229,37,151,54,49,56,251,76,65,247,216,183,176,14,144,192,96,249,111,255,27,172,183,193,56,220,227,34,127,131,245,183,157,230,60,39,253,4,211,71,205,249,231,34,204,33,96,6,16,252,22,246,165,44,23,72,168,139,37,132,91,30,249,172,0,40,32,47,9,186,44,15,55,177,186,16,228,12,171,207,12,
171,91,131,133,19,71,67,8,111,120,164,109,184,228,37,151,118,176,4,187,200,239,62,247,32,238,99,18,52,152,61,22,87,126,3,254,185,128,242,137,191,238,47,194,216,2,163,128,236,113,183,2,99,38,0,18,210,145,100,62,67,162,44,195,39,158,60,210,18,87,23,3,254,81,86,159,81,86,55,83,128,92,234,61,202,165,167,230,245,184,34,218,125,196,206,111,0,83,40,119,
12,125,55,38,193,4,242,222,126,145,179,47,226,167,195,244,169,103,238,178,46,37,203,32,248,213,151,225,249,222,7,98,229,170,30,126,53,36,20,144,151,4,93,170,143,77,57,212,65,133,63,11,153,99,117,202,9,16,75,155,229,234,76,156,63,199,133,145,11,57,174,108,18,226,84,15,59,115,66,185,189,63,238,148,98,51,203,223,231,1,73,142,179,198,229,152,3,78,103,115,
11,164,229,2,241,115,210,233,139,195,101,210,18,115,147,16,70,46,233,200,67,15,185,132,91,18,144,80,223,25,212,119,6,52,152,156,1,228,18,63,195,194,103,56,127,131,75,107,185,148,77,92,25,36,217,254,71,158,194,124,44,193,44,244,205,50,142,122,240,196,229,157,243,146,220,230,234,55,97,142,226,48,129,113,6,230,24,31,200,158,35,206,240,246,135,133,34,230,55,88,
25,212,156,191,206,192,252,197,234,98,10,245,27,5,196,234,109,50,72,240,155,44,140,60,48,185,52,6,116,25,12,114,155,75,207,112,226,248,60,100,207,215,63,197,124,44,1,249,216,49,241,137,140,50,142,178,199,61,152,4,86,14,247,239,18,198,41,99,206,204,204,135,89,62,144,61,142,115,222,254,176,80,136,252,228,145,150,154,243,82,9,243,18,252,51,144,13,48,227,2,
177,116,51,156,127,134,185,27,12,242,105,215,25,46,31,121,96,9,182,54,132,114,143,52,112,125,74,64,92,25,36,57,55,16,71,110,23,238,19,32,203,80,215,97,254,15,128,144,79,245,241,171,33,200,50,253,57,14,66,121,89,206,38,18,252,57,102,231,102,166,155,56,84,161,236,62,200,62,15,84,142,28,167,155,64,239,35,184,31,74,208,231,83,126,31,99,243,45,157,190,
109,217,24,193,120,97,144,221,159,155,208,159,49,64,252,120,219,20,79,153,124,217,86,136,116,36,97,7,113,246,54,88,91,16,127,93,141,44,180,147,29,223,96,16,151,126,134,75,51,227,2,121,221,47,127,130,235,73,2,18,108,153,19,236,38,9,140,45,106,170,152,130,219,244,128,4,187,247,225,28,185,225,81,230,129,128,178,76,48,129,125,214,177,167,113,95,146,96,226,138,
204,60,228,214,126,107,160,19,16,115,19,23,102,112,144,71,184,17,1,10,208,105,184,96,10,110,51,0,131,149,79,62,245,58,192,164,233,81,6,53,215,9,15,161,61,37,32,15,125,22,250,204,242,129,236,107,122,139,127,154,168,144,208,255,13,236,217,55,90,96,6,227,169,225,18,62,199,133,91,46,250,27,33,116,80,4,251,26,49,65,176,225,40,234,116,212,102,11,214,240,
46,52,144,238,168,71,28,217,249,183,56,238,185,187,50,14,87,48,137,48,29,41,116,142,185,45,29,243,144,203,181,90,239,193,217,51,23,136,197,145,71,30,98,238,41,184,167,34,96,72,64,246,184,239,57,62,204,45,220,16,210,24,156,52,66,230,55,132,114,140,22,243,27,39,120,253,140,16,118,25,109,172,159,17,51,196,116,154,3,120,86,99,76,32,124,98,0,247,50,91,
246,184,51,30,51,196,223,43,123,162,213,105,82,18,242,88,235,20,113,230,180,152,0,196,202,47,216,103,90,151,29,79,51,126,255,222,140,162,109,196,123,188,54,48,188,81,81,246,236,21,214,42,120,79,105,72,82,201,103,142,113,51,252,55,51,140,0,200,103,173,169,98,190,86,67,66,46,249,114,184,95,228,24,20,102,173,187,18,54,198,128,89,196,245,196,168,176,54,34,9,
253,106,23,236,143,129,220,5,168,59,160,144,107,125,11,239,125,173,144,144,144,143,236,53,133,142,123,59,160,144,250,179,57,213,149,156,224,206,73,210,95,202,48,58,148,158,166,63,135,115,121,144,167,150,240,156,203,210,17,211,223,139,61,138,94,9,200,195,254,62,148,221,39,1,121,228,159,192,51,246,4,168,216,127,203,93,235,80,38,118,57,99,231,214,91,48,39,219,113,183,
32,204,102,29,198,24,158,255,77,198,117,235,156,245,204,24,158,241,199,36,32,175,241,191,14,227,55,97,200,239,250,91,23,156,223,174,175,1,73,110,249,187,144,38,1,72,114,252,106,189,152,91,83,130,160,191,52,132,115,31,140,65,129,146,75,56,9,246,15,114,105,7,61,40,113,144,144,95,103,118,16,163,50,134,113,12,134,142,116,74,161,157,174,198,2,53,251,227,116,239,
56,25,12,164,55,66,64,17,243,27,146,229,18,99,12,239,68,198,36,24,23,202,152,132,127,18,88,25,204,217,9,209,56,31,247,0,48,195,104,0,98,250,231,16,63,7,52,60,179,107,49,51,8,74,156,44,121,64,246,245,178,102,113,250,160,60,37,46,221,160,64,73,18,98,109,80,186,164,75,25,194,94,198,144,4,228,209,255,67,17,243,87,96,79,197,131,1,159,56,98,
249,205,48,103,176,243,11,220,196,185,41,228,26,129,98,100,116,59,222,145,1,147,201,81,96,116,98,206,247,128,196,235,239,126,92,95,18,76,108,199,253,219,166,19,247,240,166,123,187,195,36,194,38,37,48,153,157,166,15,147,18,229,16,127,191,34,92,131,46,148,112,126,105,16,148,24,131,28,37,33,174,196,197,81,64,123,87,80,118,133,67,197,253,66,229,200,226,158,146,245,
33,23,64,86,72,71,156,238,254,33,172,253,4,122,113,207,233,149,128,184,114,84,206,222,177,31,161,127,37,48,240,188,101,184,80,224,254,86,171,224,1,249,180,103,29,207,178,245,54,65,46,58,251,177,222,239,247,129,2,198,131,201,205,3,21,132,152,156,223,148,100,48,32,94,67,185,26,135,233,18,166,185,196,13,10,101,80,128,253,102,130,144,135,174,2,206,46,21,124,40,
6,80,240,128,88,253,138,30,249,136,197,23,2,244,19,43,131,60,100,33,33,251,11,18,118,145,132,253,23,5,80,240,40,187,224,97,255,69,96,132,197,141,112,20,66,230,31,113,201,87,112,169,87,209,165,223,70,124,242,23,36,218,127,132,131,92,218,145,130,236,255,112,230,88,222,237,53,231,239,127,120,200,14,207,35,92,130,178,226,124,243,193,206,67,160,92,235,158,15,43,
11,84,57,134,145,110,79,94,81,166,15,177,180,118,158,26,135,100,126,130,156,150,252,134,198,52,7,241,115,72,30,247,150,8,152,104,3,179,133,181,215,77,28,166,139,223,12,1,69,88,127,61,140,246,120,152,81,103,223,36,121,88,160,140,62,209,145,90,119,153,131,171,136,171,10,232,46,84,89,223,233,62,80,27,214,155,122,128,13,122,194,246,232,33,244,235,33,108,212,99,
46,87,119,209,163,75,164,91,169,182,142,173,163,27,178,59,37,200,94,91,45,91,252,253,11,155,163,30,212,133,180,141,29,120,198,102,212,89,24,185,140,129,185,15,226,253,231,14,188,27,101,204,34,221,28,11,155,194,154,110,202,5,66,190,41,143,247,38,83,92,184,101,159,193,59,163,117,220,202,39,198,52,226,231,222,36,183,143,238,70,195,62,235,217,19,237,253,146,204,251,
52,242,193,8,200,111,36,28,191,155,189,139,24,134,187,194,189,191,169,184,161,176,119,60,77,153,119,190,211,104,83,1,212,202,252,115,16,249,219,0,37,164,139,78,144,250,82,92,247,131,26,202,11,1,185,148,161,173,234,81,180,27,241,204,20,36,111,76,152,48,122,87,5,196,1,98,245,51,217,58,103,36,223,49,207,192,78,7,59,45,185,180,135,122,61,246,6,218,4,217,
250,14,194,29,3,196,141,135,178,128,30,97,124,144,223,124,184,186,39,18,155,97,247,230,148,32,123,236,31,196,120,105,51,100,183,115,205,65,189,59,60,182,221,196,216,12,255,230,152,32,137,254,86,79,130,13,17,24,123,6,251,105,18,24,103,226,158,119,166,156,77,97,176,176,127,106,185,240,176,36,13,236,209,54,192,28,220,115,216,251,157,19,32,73,59,234,18,223,200,164,
152,235,78,130,110,139,123,166,157,98,126,75,64,195,30,160,198,24,196,121,128,65,80,98,12,2,29,225,58,71,73,56,51,80,198,255,101,23,116,198,190,154,243,109,105,62,15,241,243,75,63,198,65,140,76,76,96,207,126,158,142,121,40,160,173,6,247,161,158,28,37,6,5,228,171,236,195,122,11,12,61,129,247,55,18,144,215,245,118,10,174,27,15,114,111,196,30,185,36,89,
6,133,24,39,253,182,158,226,178,182,67,156,13,217,139,187,148,254,213,216,139,118,227,98,188,3,104,178,122,113,156,157,119,0,255,247,126,31,251,255,18,144,88,247,213,78,57,198,122,188,191,21,48,193,1,151,112,195,133,177,71,49,159,73,96,184,228,37,187,255,151,161,15,2,200,225,121,49,231,66,150,145,243,240,147,204,124,191,108,177,30,25,91,178,92,217,189,223,65,251,
74,64,205,118,95,134,118,199,115,108,63,67,59,3,239,92,129,6,40,161,249,144,24,26,211,51,0,42,12,117,61,234,37,73,118,55,218,149,145,101,244,239,70,61,128,138,248,30,70,150,165,33,73,187,140,128,231,85,35,98,60,181,160,219,144,124,94,157,138,225,27,199,133,21,139,253,246,253,106,4,165,143,184,220,55,10,24,63,133,8,168,66,127,102,133,254,204,9,125,155,
21,250,178,23,215,114,175,4,228,117,189,173,196,28,200,65,33,199,176,122,16,249,98,130,196,178,235,8,111,51,36,94,163,7,163,173,185,211,88,227,83,138,76,249,92,87,20,114,108,117,99,205,219,45,64,110,99,112,167,243,221,71,217,239,48,158,182,74,46,157,219,247,27,85,159,112,226,226,201,195,173,6,96,68,252,86,209,29,12,138,225,254,100,196,244,237,36,138,80,22,
37,124,15,54,66,218,115,251,181,206,183,51,197,189,30,179,69,42,74,39,246,73,237,189,85,251,55,158,216,239,52,225,28,111,5,12,179,247,134,149,195,222,237,96,199,15,11,178,130,235,176,2,134,5,127,133,177,139,163,210,140,207,59,229,85,176,95,85,177,169,57,236,230,202,25,246,208,83,1,85,176,155,201,42,131,236,242,106,220,111,90,177,48,10,104,127,138,105,236,25,
17,199,220,118,188,107,166,249,58,116,28,171,231,62,174,46,21,48,204,181,69,213,14,203,99,207,156,201,10,228,144,36,21,214,238,85,86,78,117,190,252,142,216,246,234,212,22,160,69,247,121,242,77,163,198,24,79,156,222,125,236,119,161,170,104,143,17,182,103,184,15,254,125,246,251,108,197,121,199,215,124,87,91,101,232,12,66,60,73,176,157,59,31,160,43,206,251,223,102,156,
133,51,91,86,8,168,133,60,86,74,101,19,87,30,69,44,155,90,108,47,43,166,252,86,4,157,196,81,193,59,171,10,131,132,184,50,254,47,39,12,113,250,116,110,44,235,94,172,144,163,204,208,57,72,86,135,178,24,59,31,53,109,92,209,158,115,16,94,232,130,109,122,27,48,185,51,44,26,246,152,181,54,67,92,253,173,46,140,229,136,80,132,246,55,217,153,170,114,155,32,
65,255,108,150,22,65,18,54,91,72,103,53,81,163,243,176,100,26,114,177,69,195,30,177,150,0,165,10,246,141,5,200,77,255,153,72,159,2,100,207,181,251,177,223,182,21,126,14,18,237,219,186,56,94,164,114,101,70,185,20,242,82,1,146,28,191,198,203,176,230,75,1,98,250,199,126,140,253,88,9,200,195,254,34,202,42,198,8,9,229,23,16,86,104,35,36,232,87,177,175,
167,250,64,1,253,171,98,61,175,70,128,66,204,133,253,49,60,175,26,88,151,24,9,65,41,234,167,152,234,79,17,219,151,130,198,203,114,244,187,11,196,197,147,79,58,53,38,136,211,65,130,125,196,185,45,140,57,43,1,8,229,207,109,195,89,63,184,103,125,208,54,164,135,109,35,249,80,70,154,114,0,20,113,188,88,43,209,94,49,65,92,121,228,162,107,22,225,179,2,218,
201,201,80,246,128,56,123,42,195,25,197,192,122,212,104,3,228,210,30,19,118,220,218,100,17,117,142,35,108,156,139,31,143,8,9,229,142,135,196,194,59,227,6,222,89,55,24,132,178,26,156,155,4,26,92,218,6,176,144,223,226,32,123,12,174,246,246,39,5,185,216,71,46,182,207,34,237,108,0,228,115,189,206,225,221,253,156,31,171,253,243,27,125,232,119,1,179,140,189,92,
238,183,19,168,217,167,125,232,35,129,137,50,206,130,184,49,43,55,23,105,120,7,162,37,0,241,215,245,118,236,127,120,96,97,14,176,18,128,154,115,220,201,232,67,31,44,60,219,88,49,65,110,115,108,63,244,248,160,194,6,53,6,200,167,143,251,17,223,207,65,33,239,73,125,200,211,231,1,69,189,223,109,68,219,5,64,17,117,144,15,7,241,204,126,48,38,168,5,253,55,
32,223,13,49,65,62,122,198,17,63,238,130,134,51,82,26,71,9,103,172,74,28,20,96,255,208,227,56,255,37,1,121,217,213,1,59,82,130,236,241,183,21,99,76,2,66,218,198,149,184,143,128,71,177,71,64,205,241,187,117,33,190,21,202,167,97,29,228,129,6,40,32,191,138,52,106,12,228,170,56,7,34,73,31,210,247,113,244,187,64,49,93,159,6,206,180,24,17,25,247,
129,98,158,79,52,236,33,104,9,65,18,250,75,231,227,186,245,160,114,62,238,185,54,25,236,115,9,144,56,46,51,24,131,17,24,122,0,215,189,4,20,161,173,75,168,83,255,37,56,159,6,40,68,190,78,238,236,136,129,177,106,68,132,124,116,141,61,137,253,54,9,200,107,60,117,161,239,61,40,93,128,126,21,24,116,9,43,9,144,61,111,127,27,237,47,65,229,2,140,23,
14,13,122,7,153,30,13,110,10,104,107,11,207,84,86,76,52,46,197,185,117,200,185,155,177,110,244,120,134,35,23,102,55,97,173,21,35,20,102,62,200,161,175,98,128,90,44,107,176,132,190,98,148,56,6,185,176,65,46,188,82,66,63,219,228,48,47,112,238,18,251,214,190,134,115,133,154,7,196,226,201,37,29,5,228,213,2,160,16,249,43,56,215,72,94,247,147,77,184,102,
35,48,58,210,117,12,51,0,114,155,15,126,130,235,93,2,242,176,63,119,17,238,193,32,203,32,132,169,120,103,170,250,64,44,175,234,225,87,67,66,1,121,73,208,165,122,164,49,243,78,93,108,127,150,213,39,199,213,45,203,213,145,64,214,195,159,229,194,84,159,247,199,89,46,29,113,168,46,246,101,133,114,115,204,182,156,11,228,210,63,57,143,120,10,96,116,15,198,22,48,
57,70,153,52,176,191,104,112,76,236,193,115,62,207,6,82,198,126,136,241,35,193,4,203,67,208,57,129,124,166,80,62,133,176,153,98,36,183,31,237,14,114,12,21,239,246,84,208,207,36,5,228,239,125,6,231,147,37,32,175,249,122,19,230,144,22,25,196,53,63,200,40,9,16,43,127,144,75,51,200,197,15,114,238,202,29,152,115,71,24,119,224,28,151,205,38,204,107,77,70,
184,248,144,104,200,175,113,148,4,251,74,187,160,223,254,230,231,46,128,111,92,106,30,223,185,36,15,134,30,193,186,65,2,242,200,63,97,127,103,244,150,112,120,149,69,45,160,158,142,113,38,73,238,114,140,85,144,99,50,203,220,57,23,178,76,170,62,191,87,69,246,248,125,10,227,83,2,74,232,250,211,58,212,182,65,205,49,215,161,30,99,144,81,18,24,116,9,43,113,101,
80,115,252,221,135,241,37,65,25,121,203,160,130,119,82,21,134,14,191,218,141,190,13,65,182,128,190,101,228,36,200,114,238,126,228,39,193,254,35,152,155,142,72,48,139,185,112,54,0,10,217,247,22,242,88,246,59,192,229,238,28,75,183,124,177,59,40,143,229,226,182,90,100,230,194,46,87,8,101,207,112,110,2,13,184,27,44,172,1,44,150,223,98,178,1,230,46,196,30,61,
131,36,218,232,200,119,209,254,18,144,87,27,175,71,61,124,32,201,116,86,4,102,118,163,77,24,13,1,106,182,221,110,199,207,167,157,97,97,22,202,152,187,21,207,96,172,44,74,104,46,34,23,42,47,199,253,239,205,184,94,121,238,6,8,47,189,57,216,22,11,207,235,13,236,97,53,92,152,97,52,56,44,164,183,56,230,238,196,88,169,58,4,233,162,4,80,237,119,6,253,
201,226,167,223,34,180,67,0,36,153,206,138,200,204,121,232,35,31,200,30,199,231,185,199,53,243,90,40,103,238,60,244,167,0,73,246,199,145,111,225,122,151,96,22,122,102,91,132,56,125,115,227,176,111,188,67,177,240,238,207,138,1,106,94,239,101,180,71,11,144,61,239,150,253,211,240,241,51,66,94,10,192,192,57,71,195,3,226,226,41,32,173,17,1,83,195,243,151,11,196,
217,105,50,191,201,197,153,30,249,76,96,176,114,41,160,254,99,22,158,215,36,32,143,252,26,244,104,46,16,23,71,62,233,180,152,24,68,93,7,5,8,122,75,144,37,230,30,100,225,37,78,106,30,231,92,137,49,132,186,15,73,64,73,205,199,125,152,51,99,34,135,107,34,7,178,140,126,132,245,3,138,211,222,147,162,149,247,196,199,157,223,182,141,10,181,160,123,238,114,156,
15,194,187,54,163,13,144,135,13,55,35,238,230,22,33,228,159,192,187,195,9,1,10,209,6,134,164,157,148,16,22,158,89,172,22,33,228,191,191,187,195,7,69,185,191,16,80,127,252,173,173,225,1,181,163,254,157,168,75,194,144,159,254,117,72,147,18,4,253,71,176,119,115,68,2,18,175,221,93,88,183,0,138,216,254,170,253,205,118,138,78,179,188,28,214,128,57,129,254,16,
235,191,105,140,187,105,142,185,157,25,229,104,136,177,120,228,123,104,47,9,8,105,103,81,238,172,7,100,143,141,85,232,167,152,33,183,49,184,42,217,242,195,208,135,51,139,125,9,209,255,6,188,91,182,89,11,55,32,183,249,232,100,204,61,146,144,144,215,28,198,58,16,225,163,144,163,45,66,62,109,99,34,222,228,56,0,93,7,66,210,243,166,14,165,103,175,243,183,196,3,
192,204,5,127,115,138,103,176,136,181,28,160,86,175,247,79,224,122,77,16,10,208,111,224,221,167,145,0,20,99,253,41,226,53,68,62,104,73,127,51,243,70,111,252,236,34,89,251,87,57,223,210,228,191,167,73,33,48,132,239,61,82,80,127,221,134,62,105,35,36,218,219,141,241,37,9,185,213,183,91,62,191,95,57,20,178,60,98,233,39,225,54,177,55,110,130,137,66,230,184,
239,237,83,130,99,157,92,208,241,191,158,0,20,131,126,74,216,70,61,164,173,212,74,251,174,112,254,118,188,132,247,228,37,134,14,63,181,169,127,203,248,191,28,35,116,130,140,47,93,210,150,114,204,245,47,135,108,147,34,254,47,182,64,193,7,66,185,133,128,52,5,70,81,162,188,66,140,20,153,125,69,206,77,204,79,66,155,144,71,27,145,68,187,21,60,218,132,2,218,134,
66,180,93,161,197,190,43,250,216,89,244,169,35,73,142,25,10,72,67,33,235,88,136,216,223,69,159,250,20,125,236,39,201,235,132,98,168,15,69,188,30,139,45,244,119,53,160,221,10,156,93,67,135,177,143,27,3,147,167,210,34,204,125,93,199,220,19,251,176,31,199,115,106,180,251,144,93,182,41,64,30,225,166,36,20,241,126,151,195,158,122,206,3,10,136,207,73,66,33,117,
145,71,90,74,224,126,175,102,177,110,14,9,241,237,55,8,219,60,232,65,218,30,15,136,229,239,157,193,249,29,9,200,197,238,205,45,254,141,17,241,229,108,69,157,66,144,187,18,117,227,232,253,25,236,147,128,92,116,159,122,101,167,162,97,31,69,19,160,230,90,100,45,214,11,1,148,222,128,53,162,7,36,81,255,41,252,63,197,209,192,51,69,195,131,105,110,254,33,198,17,
204,33,71,36,32,33,223,28,131,98,160,140,255,203,45,162,215,112,246,137,243,239,19,252,101,151,58,83,130,246,148,99,66,143,152,159,88,93,140,14,60,143,114,144,75,152,145,32,196,233,35,230,38,206,54,10,97,15,249,212,135,132,178,73,192,112,137,51,60,242,27,45,216,79,18,229,145,75,126,35,68,223,144,100,30,138,169,109,141,22,251,155,92,218,217,8,208,67,9,234,
167,16,220,137,50,238,140,80,142,206,190,193,168,75,66,2,122,204,80,72,244,24,116,233,17,203,208,219,0,73,183,71,119,11,80,236,223,141,214,149,229,237,225,198,214,199,142,211,94,212,86,168,5,253,36,97,63,197,92,127,106,19,122,30,125,24,166,13,243,225,210,7,234,175,69,235,195,200,249,149,120,9,221,254,74,2,248,212,151,34,182,31,197,140,30,178,110,20,115,251,
81,76,246,81,139,249,169,77,227,131,132,254,166,86,251,171,150,32,108,110,161,8,101,80,179,156,60,67,244,231,37,137,88,23,242,169,7,121,196,147,11,186,132,14,242,65,143,1,106,177,124,106,1,61,106,125,149,24,175,25,123,125,174,132,207,19,133,33,201,125,92,242,42,163,22,255,28,45,133,226,232,79,227,247,24,181,132,127,31,134,66,180,131,22,241,247,99,180,151,248,
111,215,104,105,219,169,56,191,63,224,121,125,40,201,98,255,77,191,25,1,138,168,63,147,239,78,5,98,250,235,61,148,42,197,101,233,34,254,6,104,61,38,57,21,64,157,251,173,181,130,15,197,0,10,17,243,235,236,62,88,180,101,205,249,109,208,249,61,14,133,133,177,240,2,243,23,25,5,70,145,15,171,113,249,240,251,36,58,123,103,90,116,65,231,169,177,125,21,46,174,
200,108,43,50,127,221,110,179,67,221,139,242,23,184,242,234,107,28,105,135,105,2,5,78,87,65,200,87,117,161,200,165,43,112,249,171,92,57,83,107,28,121,220,222,124,173,219,65,241,136,19,220,43,213,116,177,219,109,202,229,55,113,167,2,198,120,221,227,55,116,167,2,174,129,105,70,189,201,50,132,131,122,74,178,184,28,253,11,138,33,165,6,74,23,118,41,23,115,84,88,
88,73,130,10,210,14,180,160,183,24,81,14,48,74,204,142,17,140,193,17,197,233,11,190,239,234,33,231,185,122,76,114,58,196,220,89,23,198,227,148,132,28,96,245,29,113,169,179,21,115,253,234,30,215,73,221,231,250,169,7,200,10,214,76,245,67,237,193,254,109,175,10,244,237,201,43,243,191,61,181,11,20,113,222,181,152,34,133,132,57,24,227,247,85,15,182,64,253,204,116,
89,137,51,11,43,83,164,136,235,178,216,6,10,9,81,124,137,219,95,144,168,79,181,77,186,171,41,183,115,245,247,164,94,213,4,251,168,126,130,48,149,22,61,237,163,2,125,211,98,248,26,119,92,159,7,151,47,172,191,227,98,0,229,14,128,105,143,240,1,142,41,15,91,167,124,24,88,238,31,159,36,211,46,20,2,158,183,47,10,160,16,49,255,84,27,199,219,148,27,107,
218,135,189,70,159,134,156,230,40,224,153,173,144,34,35,88,3,79,97,109,60,213,6,134,177,254,174,178,245,119,181,230,248,163,174,111,45,156,17,183,34,112,67,140,223,255,191,161,5,166,176,70,157,74,145,110,172,81,187,83,196,58,37,25,26,111,196,25,98,142,105,151,176,6,48,48,31,27,192,196,222,129,105,239,99,228,157,223,138,29,251,110,167,20,19,200,123,128,149,97,
180,194,186,5,14,112,110,163,93,108,76,150,3,30,76,236,205,204,51,45,204,135,211,109,96,128,187,135,79,167,160,127,154,179,227,178,195,138,178,23,12,99,46,220,131,121,113,216,67,86,216,184,172,52,169,117,204,239,253,84,154,126,69,112,11,236,62,156,153,167,194,151,161,144,178,127,222,173,28,251,125,115,29,12,20,59,20,13,242,82,188,35,27,14,176,107,152,73,157,229,
29,14,72,183,59,223,113,204,189,135,229,187,20,122,46,13,192,20,222,83,101,139,14,246,111,179,15,136,228,187,142,217,115,41,87,198,128,93,175,188,243,219,239,205,120,227,38,14,251,111,204,111,114,145,110,172,14,136,115,137,175,64,247,128,210,163,28,184,184,99,30,3,97,234,221,241,211,243,230,14,249,244,39,37,75,143,7,253,151,102,230,49,112,15,50,66,112,0,76,236,
199,220,241,201,142,121,105,132,204,111,8,140,224,26,24,73,136,1,9,140,245,106,36,14,248,196,77,114,24,96,20,152,76,26,140,61,236,218,31,62,54,207,40,243,227,212,224,199,241,106,111,236,241,108,120,93,7,55,181,143,129,230,247,81,46,116,238,227,54,163,192,136,114,111,94,222,58,77,253,38,179,97,148,249,71,57,251,76,15,70,5,76,206,109,216,101,231,133,247,246,
92,94,35,192,46,21,247,124,181,77,228,118,117,205,163,194,157,133,204,2,107,11,41,71,239,202,28,99,206,102,11,57,242,46,219,221,177,224,190,162,233,119,1,225,71,231,243,117,204,203,163,140,198,21,88,215,129,163,92,216,81,14,35,226,245,102,196,200,40,119,77,154,28,163,46,97,166,75,220,168,224,55,192,216,163,88,151,74,48,177,27,115,168,205,122,204,167,28,134,164,
173,134,128,41,196,141,114,24,46,97,163,30,105,12,151,58,27,45,96,186,216,60,234,129,201,217,55,38,217,126,163,66,254,73,134,90,92,150,46,7,83,166,158,46,6,246,116,140,20,185,245,2,172,73,240,187,76,198,9,196,36,152,136,171,188,83,210,69,205,225,26,75,145,28,35,203,185,115,46,100,25,70,26,207,244,235,22,99,226,190,107,2,67,8,55,146,224,116,212,57,
69,180,53,233,98,110,71,91,115,140,2,163,19,237,210,38,76,166,211,116,97,148,147,163,140,156,238,144,5,234,102,92,95,41,144,101,54,228,56,178,140,28,231,207,113,168,44,111,239,209,78,41,84,15,221,26,165,139,218,155,46,214,25,233,178,232,155,131,171,122,218,254,141,195,221,246,179,238,106,143,125,31,81,222,148,48,237,210,115,211,2,42,246,197,212,52,185,62,93,194,
252,189,128,150,0,106,2,251,127,106,8,140,136,251,103,70,68,172,54,124,207,219,242,65,179,239,1,155,113,126,20,247,20,13,82,99,148,4,191,230,17,166,69,196,232,79,151,193,125,93,243,104,120,23,170,165,192,32,211,63,40,137,41,177,127,102,74,96,120,236,143,77,112,24,182,252,16,158,231,184,61,189,161,239,119,74,161,173,70,253,18,164,116,49,206,59,251,80,177,223,
235,92,156,81,84,251,153,233,148,214,201,161,172,28,35,11,84,232,86,83,34,199,108,200,114,54,229,56,219,178,46,126,21,103,28,212,20,209,206,192,115,65,138,148,56,89,226,252,154,139,95,115,137,83,177,39,168,166,73,29,125,184,18,123,59,237,162,222,94,125,113,124,67,200,0,119,180,136,145,18,123,216,59,39,203,126,6,233,77,17,236,105,89,105,146,77,23,109,107,186,
68,57,187,101,197,128,138,61,91,53,77,58,210,197,192,53,96,164,136,245,178,228,56,202,152,245,193,178,207,160,173,77,15,213,30,131,167,182,151,62,70,191,237,223,208,126,250,56,140,62,127,38,3,226,141,136,104,246,51,96,103,122,88,56,11,103,165,136,134,53,190,150,34,150,125,15,216,154,30,218,105,237,167,204,49,120,62,158,215,192,32,208,50,136,111,51,37,166,191,228,
65,238,18,135,44,80,113,102,81,109,51,89,166,59,203,236,200,113,100,133,240,126,164,239,7,157,182,188,4,231,203,64,233,2,212,131,161,97,189,165,181,153,220,8,108,3,89,160,110,66,157,82,36,203,236,200,50,155,114,1,100,61,236,238,31,65,219,218,108,114,220,98,190,126,132,103,153,187,247,39,120,255,34,129,106,151,117,7,246,43,88,153,253,12,3,126,35,37,76,216,
111,216,247,168,13,233,50,186,7,239,234,24,102,0,42,246,84,213,20,201,238,199,152,97,228,60,200,114,50,43,164,215,208,238,90,154,172,75,151,65,188,167,31,100,148,2,24,228,210,13,50,169,158,142,126,72,147,238,116,209,216,239,208,151,36,208,144,86,75,144,146,135,222,65,166,187,36,132,87,238,206,28,247,123,247,86,74,52,170,56,71,25,146,25,206,61,87,197,217,77,
134,133,242,230,238,132,27,168,62,191,123,175,182,1,3,107,62,35,69,44,140,81,43,85,148,5,10,28,98,186,130,24,214,76,231,145,62,105,155,11,238,122,189,126,139,216,104,59,138,98,236,4,17,203,177,82,166,177,19,215,175,7,115,59,113,13,55,89,133,107,26,28,21,48,66,252,30,171,145,0,106,194,191,87,170,6,96,36,244,123,165,134,44,55,225,222,211,230,51,52,
154,15,106,155,127,143,83,21,48,236,57,162,59,61,90,249,189,35,53,78,182,166,139,248,91,67,90,155,49,183,225,185,8,108,87,22,220,237,228,200,211,157,82,204,110,193,126,180,4,71,175,200,28,251,251,150,6,39,31,219,162,40,63,188,66,57,38,103,16,54,3,74,56,179,80,74,17,83,252,91,165,188,28,205,252,149,26,206,232,49,118,49,134,37,255,38,117,24,82,71,
191,235,2,131,40,127,80,208,167,187,196,15,10,108,15,192,12,64,103,229,155,18,105,244,152,49,19,210,99,70,248,45,61,51,102,38,241,62,99,146,195,140,169,156,73,151,114,39,3,210,76,50,70,35,252,182,252,104,12,12,197,244,187,141,67,45,242,240,161,238,112,172,161,197,28,106,49,31,227,210,21,233,83,22,208,125,184,25,247,204,155,83,164,220,252,222,107,45,29,100,
127,179,168,156,4,10,250,0,223,98,208,109,89,235,96,208,162,249,110,56,196,189,103,15,39,203,73,181,151,178,216,190,32,202,168,79,89,2,61,33,202,129,253,79,210,54,150,19,178,187,28,129,113,172,57,199,83,100,22,123,176,179,49,115,52,128,39,62,222,121,140,178,61,198,148,20,105,105,206,33,142,238,72,236,199,185,219,253,94,40,29,139,252,219,149,46,229,58,172,197,
174,59,188,252,216,26,114,55,194,119,35,221,110,91,230,157,111,182,236,70,185,21,27,101,241,247,98,108,247,101,130,191,194,165,173,216,28,230,64,121,111,58,220,173,92,1,182,187,172,95,247,67,111,165,214,233,143,178,96,195,188,158,60,242,216,40,88,155,51,42,28,85,165,147,251,182,68,199,162,244,21,31,170,76,238,106,134,229,133,111,220,52,81,22,194,230,219,52,31,188,
78,79,146,76,74,191,127,144,97,116,229,213,84,169,216,227,226,240,194,184,60,54,86,14,47,192,135,93,214,116,231,133,126,117,233,231,221,243,82,153,247,239,182,251,93,225,198,34,220,21,137,251,223,176,248,221,34,197,35,109,208,189,181,198,16,194,171,12,221,135,225,32,221,74,235,52,245,87,57,134,153,190,170,71,124,53,1,134,37,215,69,213,20,116,14,135,148,213,20,219,
173,218,70,221,85,143,177,162,115,99,75,119,113,235,30,227,80,143,145,170,168,191,230,92,159,77,169,39,68,53,44,181,238,5,89,99,110,62,174,198,133,241,110,69,200,139,223,27,169,218,40,46,233,196,176,26,43,183,137,226,82,94,83,214,92,224,211,40,46,122,196,180,138,79,157,130,168,121,212,57,40,157,18,162,124,62,111,205,167,109,252,252,74,68,226,44,191,38,217,102,
178,241,74,140,117,140,171,44,37,6,14,71,47,35,169,121,68,247,160,154,130,78,157,211,93,141,25,253,4,169,131,222,42,53,129,208,249,187,23,214,142,53,230,118,67,9,81,14,243,87,221,242,213,66,166,19,210,234,110,241,53,9,251,100,237,175,133,40,79,34,93,53,0,157,215,87,19,244,207,187,201,61,141,226,204,103,209,234,76,137,141,231,106,8,244,128,178,244,192,122,
116,75,247,223,62,172,81,246,121,81,243,137,11,162,22,16,198,220,186,120,189,214,146,99,164,182,252,56,54,227,204,197,230,20,209,35,142,55,61,42,53,151,177,210,78,148,54,216,35,234,80,18,108,15,175,114,20,89,253,2,243,97,221,199,151,173,120,216,125,92,56,45,158,51,107,112,47,10,167,197,191,87,173,180,1,94,183,34,198,177,58,132,237,55,37,110,27,61,218,179,
221,237,83,147,161,217,183,62,125,220,12,175,137,233,197,48,209,205,245,147,239,245,74,62,215,5,121,216,76,194,248,235,246,73,79,238,99,166,198,16,127,127,93,17,210,37,65,13,182,242,254,195,216,19,20,152,204,224,28,65,138,232,7,83,166,217,63,181,116,216,12,27,54,167,132,30,131,253,147,56,15,58,153,18,122,202,250,39,153,13,186,95,255,222,157,46,126,103,65,244,
54,48,41,121,142,105,50,33,116,123,14,172,181,0,63,135,214,98,96,209,188,76,194,125,166,59,2,116,60,121,110,189,20,55,10,35,201,121,81,241,209,225,21,158,231,238,173,110,237,144,119,137,143,147,188,139,110,89,106,49,234,143,131,90,192,88,18,211,230,37,235,210,140,207,71,168,115,179,255,21,137,241,224,151,87,137,56,54,221,168,69,196,175,108,37,65,187,101,168,37,
132,221,79,121,143,49,22,87,249,53,73,157,113,160,180,185,29,91,209,147,247,185,214,69,148,136,227,198,139,195,220,115,8,206,235,232,77,20,159,122,136,246,214,90,28,15,110,117,175,181,216,159,34,121,143,251,143,23,249,22,239,13,126,113,97,202,23,245,200,232,142,10,95,190,232,22,210,138,255,254,63,0,0,0,255,255,0,0,0,255,255,99,102,0,0};
}
}

5
src/Avalonia.PlatformSupport/AssetLoader.cs → src/Avalonia.Base/Platform/AssetLoader.cs

@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Avalonia.Platform; using Avalonia.Platform.Internal;
using Avalonia.PlatformSupport.Internal;
using Avalonia.Utilities; using Avalonia.Utilities;
namespace Avalonia.PlatformSupport namespace Avalonia.Platform
{ {
/// <summary> /// <summary>
/// Loads assets compiled into the application binary. /// Loads assets compiled into the application binary.

7
src/Avalonia.Base/Platform/IPlatformRenderInterface.cs

@ -58,6 +58,13 @@ namespace Avalonia.Platform
/// <returns>A combined geometry.</returns> /// <returns>A combined geometry.</returns>
IGeometryImpl CreateCombinedGeometry(GeometryCombineMode combineMode, Geometry g1, Geometry g2); IGeometryImpl CreateCombinedGeometry(GeometryCombineMode combineMode, Geometry g1, Geometry g2);
/// <summary>
/// Created a geometry implementation for the glyph run.
/// </summary>
/// <param name="glyphRun">The glyph run to build a geometry from.</param>
/// <returns>The geometry returned contains the combined geometry of all glyphs in the glyph run.</returns>
IGeometryImpl BuildGlyphRunGeometry(GlyphRun glyphRun);
/// <summary> /// <summary>
/// Creates a renderer. /// Creates a renderer.
/// </summary> /// </summary>

2
src/Avalonia.PlatformSupport/Internal/AssemblyDescriptor.cs → src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs

@ -4,7 +4,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Avalonia.Utilities; using Avalonia.Utilities;
namespace Avalonia.PlatformSupport.Internal; namespace Avalonia.Platform.Internal;
internal interface IAssemblyDescriptor internal interface IAssemblyDescriptor
{ {

6
src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs → src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs

@ -2,8 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
namespace Avalonia.PlatformSupport.Internal; namespace Avalonia.Platform.Internal;
internal interface IAssemblyDescriptorResolver internal interface IAssemblyDescriptorResolver
{ {
@ -29,9 +30,8 @@ internal class AssemblyDescriptorResolver: IAssemblyDescriptorResolver
} }
else else
{ {
// iOS does not support loading assemblies dynamically!
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
if (OperatingSystem.IsIOS()) if (!RuntimeFeature.IsDynamicCodeSupported)
{ {
throw new InvalidOperationException( throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); $"Assembly {name} needs to be referenced and explicitly loaded before loading resources");

2
src/Avalonia.PlatformSupport/Internal/AssetDescriptor.cs → src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs

@ -2,7 +2,7 @@
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
namespace Avalonia.PlatformSupport.Internal; namespace Avalonia.Platform.Internal;
internal interface IAssetDescriptor internal interface IAssetDescriptor
{ {

2
src/Avalonia.PlatformSupport/Internal/Constants.cs → src/Avalonia.Base/Platform/Internal/Constants.cs

@ -1,4 +1,4 @@
namespace Avalonia.PlatformSupport.Internal; namespace Avalonia.Platform.Internal;
internal static class Constants internal static class Constants
{ {

58
src/Avalonia.PlatformSupport/DynLoader.cs → src/Avalonia.Base/Platform/Internal/DynLoader.cs

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace Avalonia.PlatformSupport namespace Avalonia.Platform.Internal
{ {
class UnixLoader : IDynamicLibraryLoader class UnixLoader : IDynamicLibraryLoader
{ {
@ -26,25 +26,6 @@ namespace Avalonia.PlatformSupport
} }
} }
static class AndroidImports
{
[DllImport("libdl.so")]
private static extern IntPtr dlopen(string path, int flags);
[DllImport("libdl.so")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so")]
private static extern IntPtr dlerror();
public static void Init()
{
DlOpen = dlopen;
DlSym = dlsym;
DlError = dlerror;
}
}
static class OsXImports static class OsXImports
{ {
[DllImport("/usr/lib/libSystem.dylib")] [DllImport("/usr/lib/libSystem.dylib")]
@ -77,10 +58,6 @@ namespace Avalonia.PlatformSupport
Marshal.FreeHGlobal(buffer); Marshal.FreeHGlobal(buffer);
if (unixName == "Darwin") if (unixName == "Darwin")
OsXImports.Init(); OsXImports.Init();
#if NET6_0_OR_GREATER
else if (OperatingSystem.IsAndroid())
AndroidImports.Init();
#endif
else else
LinuxImports.Init(); LinuxImports.Init();
} }
@ -135,6 +112,39 @@ namespace Avalonia.PlatformSupport
return ptr; return ptr;
} }
} }
#if NET6_0_OR_GREATER
internal class Net6Loader : IDynamicLibraryLoader
{
public IntPtr LoadLibrary(string dll)
{
try
{
return NativeLibrary.Load(dll);
}
catch (Exception ex)
{
throw new DynamicLibraryLoaderException("Error loading " + dll, ex);
}
}
public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional)
{
try
{
if (optional)
{
return NativeLibrary.TryGetExport(dll, proc, out var address) ? address : default;
}
return NativeLibrary.GetExport(dll, proc);
}
catch (Exception ex)
{
throw new DynamicLibraryLoaderException("Error " + dll, ex);
}
}
}
#endif
internal class NotSupportedLoader : IDynamicLibraryLoader internal class NotSupportedLoader : IDynamicLibraryLoader
{ {

2
src/Avalonia.PlatformSupport/Internal/SlicedStream.cs → src/Avalonia.Base/Platform/Internal/SlicedStream.cs

@ -1,7 +1,7 @@
using System; using System;
using System.IO; using System.IO;
namespace Avalonia.PlatformSupport.Internal; namespace Avalonia.Platform.Internal;
internal class SlicedStream : Stream internal class SlicedStream : Stream
{ {

155
src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.Platform.Internal;
internal class UnmanagedBlob : IUnmanagedBlob
{
private IntPtr _address;
private readonly object _lock = new object();
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread? GCThread;
private readonly string _backtrace;
private static readonly object _btlock = new object();
class GCThreadDetector
{
~GCThreadDetector()
{
GCThread = Thread.CurrentThread;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(int size)
{
try
{
if (size <= 0)
throw new ArgumentException("Positive number required", nameof(size));
_address = Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
}
catch
{
GC.SuppressFinalize(this);
throw;
}
#if DEBUG
_backtrace = Environment.StackTrace;
lock (_btlock)
Backtraces.Add(_backtrace);
#endif
}
void DoDispose()
{
lock (_lock)
{
if (!IsDisposed)
{
#if DEBUG
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
Free(_address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
_address = IntPtr.Zero;
Size = 0;
}
}
}
public void Dispose()
{
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
lock (_lock)
{
if (!IsDisposed)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
}
}
#endif
DoDispose();
GC.SuppressFinalize(this);
}
~UnmanagedBlob()
{
#if DEBUG
Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
#endif
DoDispose();
}
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
private static extern int munmap(IntPtr addr, IntPtr length);
[DllImport("libc", SetLastError = true)]
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
=> _useMmap ?? ((_useMmap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)).Value);
// Could be replaced with https://github.com/dotnet/runtime/issues/40892 when it will be available.
private IntPtr Alloc(int size)
{
if (!UseMmap)
{
return Marshal.AllocHGlobal(size);
}
else
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
}
return rv;
}
}
private void Free(IntPtr ptr, int len)
{
if (!UseMmap)
{
Marshal.FreeHGlobal(ptr);
}
else
{
if (munmap(ptr, new IntPtr(len)) == -1)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to free memory: " + errno);
}
}
}
}

5
src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs

@ -16,5 +16,10 @@ namespace Avalonia.Platform.Interop
{ {
} }
public DynamicLibraryLoaderException(string message, Exception innerException) : base(message, innerException)
{
}
} }
} }

58
src/Avalonia.Base/Platform/StandardRuntimePlatform.cs

@ -0,0 +1,58 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform.Internal;
namespace Avalonia.Platform
{
public class StandardRuntimePlatform : IRuntimePlatform
{
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
return new Timer(_ => tick(), null, interval, interval);
}
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(size);
private static readonly Lazy<RuntimePlatformInfo> Info = new(() =>
{
OperatingSystemType os;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
os = OperatingSystemType.OSX;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
os = OperatingSystemType.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
os = OperatingSystemType.WinNT;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Android")))
os = OperatingSystemType.Android;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("iOS")))
os = OperatingSystemType.iOS;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Browser")))
os = OperatingSystemType.Browser;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
// Source: https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
var isCoreClr = Environment.Version.Major >= 5 || RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase);
var isMonoRuntime = Type.GetType("Mono.Runtime") != null;
var isFramework = !isCoreClr && RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase);
return new RuntimePlatformInfo
{
IsCoreClr = isCoreClr,
IsDotNetFramework = isFramework,
IsMono = isMonoRuntime,
IsDesktop = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.WinNT,
IsMobile = os is OperatingSystemType.Android or OperatingSystemType.iOS,
IsUnix = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.Android,
IsBrowser = os == OperatingSystemType.Browser,
OperatingSystem = os,
};
});
public virtual RuntimePlatformInfo GetRuntimeInfo() => Info.Value;
}
}

15
src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs → src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs

@ -1,30 +1,33 @@
using System.Reflection; using System.Reflection;
using Avalonia.Platform; using Avalonia.Platform.Internal;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
namespace Avalonia.PlatformSupport namespace Avalonia.Platform
{ {
public static class StandardRuntimePlatformServices public static class StandardRuntimePlatformServices
{ {
public static void Register(Assembly? assembly = null) public static void Register(Assembly? assembly = null)
{ {
var standardPlatform = new StandardRuntimePlatform(); var standardPlatform = new StandardRuntimePlatform();
var os = standardPlatform.GetRuntimeInfo().OperatingSystem;
AssetLoader.RegisterResUriParsers(); AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform) .Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly)) .Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))
.Bind<IDynamicLibraryLoader>().ToConstant( .Bind<IDynamicLibraryLoader>().ToConstant(
os switch #if NET6_0_OR_GREATER
new Net6Loader()
#else
standardPlatform.GetRuntimeInfo().OperatingSystem switch
{ {
OperatingSystemType.WinNT => new Win32Loader(), OperatingSystemType.WinNT => (IDynamicLibraryLoader)new Win32Loader(),
OperatingSystemType.OSX => new UnixLoader(), OperatingSystemType.OSX => new UnixLoader(),
OperatingSystemType.Linux => new UnixLoader(), OperatingSystemType.Linux => new UnixLoader(),
OperatingSystemType.Android => new UnixLoader(), OperatingSystemType.Android => new UnixLoader(),
// iOS, WASM, ... // iOS, WASM, ...
_ => (IDynamicLibraryLoader)new NotSupportedLoader() _ => new NotSupportedLoader()
} }
#endif
); );
} }
} }

14
src/Avalonia.Base/Properties/AssemblyInfo.cs

@ -17,3 +17,17 @@ using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls.ColorPicker, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Web.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

1
src/Avalonia.Base/PropertyStore/PriorityValue.cs

@ -121,6 +121,7 @@ namespace Avalonia.PropertyStore
public void ClearLocalValue() public void ClearLocalValue()
{ {
_localValue = default;
UpdateEffectiveValue(new AvaloniaPropertyChangedEventArgs<T>( UpdateEffectiveValue(new AvaloniaPropertyChangedEventArgs<T>(
_owner, _owner,
Property, Property,

6
src/Avalonia.Base/Reactive/TypedBindingAdapter.cs

@ -30,13 +30,15 @@ namespace Avalonia.Reactive
} }
catch (InvalidCastException e) catch (InvalidCastException e)
{ {
var unwrappedValue = value.HasValue ? value.Value : null;
Logger.TryGet(LogEventLevel.Error, LogArea.Binding)?.Log( Logger.TryGet(LogEventLevel.Error, LogArea.Binding)?.Log(
_target, _target,
"Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})", "Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
_property.Name, _property.Name,
_property.PropertyType, _property.PropertyType,
value.Value, unwrappedValue,
value.Value?.GetType()); unwrappedValue?.GetType());
PublishNext(BindingValue<T>.BindingError(e)); PublishNext(BindingValue<T>.BindingError(e));
} }
} }

27
src/Avalonia.Base/Styling/PropertySetterInstance.cs

@ -18,7 +18,7 @@ namespace Avalonia.Styling
private readonly DirectPropertyBase<T>? _directProperty; private readonly DirectPropertyBase<T>? _directProperty;
private readonly T _value; private readonly T _value;
private IDisposable? _subscription; private IDisposable? _subscription;
private bool _isActive; private State _state;
public PropertySetterInstance( public PropertySetterInstance(
IStyleable target, IStyleable target,
@ -40,6 +40,8 @@ namespace Avalonia.Styling
_value = value; _value = value;
} }
private bool IsActive => _state == State.Active;
public void Start(bool hasActivator) public void Start(bool hasActivator)
{ {
if (hasActivator) if (hasActivator)
@ -70,31 +72,35 @@ namespace Avalonia.Styling
public void Activate() public void Activate()
{ {
if (!_isActive) if (!IsActive)
{ {
_isActive = true; _state = State.Active;
PublishNext(); PublishNext();
} }
} }
public void Deactivate() public void Deactivate()
{ {
if (_isActive) if (IsActive)
{ {
_isActive = false; _state = State.Inactive;
PublishNext(); PublishNext();
} }
} }
public override void Dispose() public override void Dispose()
{ {
if (_state == State.Disposed)
return;
_state = State.Disposed;
if (_subscription is object) if (_subscription is object)
{ {
var sub = _subscription; var sub = _subscription;
_subscription = null; _subscription = null;
sub.Dispose(); sub.Dispose();
} }
else if (_isActive) else if (IsActive)
{ {
if (_styledProperty is object) if (_styledProperty is object)
{ {
@ -114,7 +120,14 @@ namespace Avalonia.Styling
private void PublishNext() private void PublishNext()
{ {
PublishNext(_isActive ? new BindingValue<T>(_value) : default); PublishNext(IsActive ? new BindingValue<T>(_value) : default);
}
private enum State
{
Inactive,
Active,
Disposed,
} }
} }
} }

95
src/Avalonia.Base/Styling/Styles.cs

@ -17,7 +17,7 @@ namespace Avalonia.Styling
IStyle, IStyle,
IResourceProvider IResourceProvider
{ {
private readonly AvaloniaList<IStyle> _styles = new AvaloniaList<IStyle>(); private readonly AvaloniaList<IStyle> _styles = new();
private IResourceHost? _owner; private IResourceHost? _owner;
private IResourceDictionary? _resources; private IResourceDictionary? _resources;
private StyleCache? _cache; private StyleCache? _cache;
@ -62,16 +62,18 @@ namespace Avalonia.Styling
{ {
value = value ?? throw new ArgumentNullException(nameof(Resources)); value = value ?? throw new ArgumentNullException(nameof(Resources));
if (Owner is object) var currentOwner = Owner;
if (currentOwner is not null)
{ {
_resources?.RemoveOwner(Owner); _resources?.RemoveOwner(currentOwner);
} }
_resources = value; _resources = value;
if (Owner is object) if (currentOwner is not null)
{ {
_resources.AddOwner(Owner); _resources.AddOwner(currentOwner);
} }
} }
} }
@ -89,7 +91,7 @@ namespace Avalonia.Styling
foreach (var i in this) foreach (var i in this)
{ {
if (i is IResourceProvider p && p.HasResources) if (i is IResourceProvider { HasResources: true })
{ {
return true; return true;
} }
@ -190,7 +192,7 @@ namespace Avalonia.Styling
{ {
owner = owner ?? throw new ArgumentNullException(nameof(owner)); owner = owner ?? throw new ArgumentNullException(nameof(owner));
if (Owner != null) if (Owner is not null)
{ {
throw new InvalidOperationException("The Styles already has a owner."); throw new InvalidOperationException("The Styles already has a owner.");
} }
@ -227,70 +229,81 @@ namespace Avalonia.Styling
} }
} }
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) private static IReadOnlyList<T> ToReadOnlyList<T>(ICollection list)
{ {
static IReadOnlyList<T> ToReadOnlyList<T>(IList list) if (list is IReadOnlyList<T> readOnlyList)
{ {
if (list is IReadOnlyList<T>) return readOnlyList;
{
return (IReadOnlyList<T>)list;
}
else
{
var result = new T[list.Count];
list.CopyTo(result, 0);
return result;
}
} }
void Add(IList items) var result = new T[list.Count];
list.CopyTo(result, 0);
return result;
}
private static void InternalAdd(IList items, IResourceHost? owner, ref StyleCache? cache)
{
if (owner is not null)
{ {
for (var i = 0; i < items.Count; ++i) for (var i = 0; i < items.Count; ++i)
{ {
var style = (IStyle)items[i]!; if (items[i] is IResourceProvider provider)
if (Owner is object && style is IResourceProvider resourceProvider)
{ {
resourceProvider.AddOwner(Owner); provider.AddOwner(owner);
} }
_cache = null;
} }
(Owner as IStyleHost)?.StylesAdded(ToReadOnlyList<IStyle>(items)); (owner as IStyleHost)?.StylesAdded(ToReadOnlyList<IStyle>(items));
}
if (items.Count > 0)
{
cache = null;
} }
}
void Remove(IList items) private static void InternalRemove(IList items, IResourceHost? owner, ref StyleCache? cache)
{
if (owner is not null)
{ {
for (var i = 0; i < items.Count; ++i) for (var i = 0; i < items.Count; ++i)
{ {
var style = (IStyle)items[i]!; if (items[i] is IResourceProvider provider)
if (Owner is object && style is IResourceProvider resourceProvider)
{ {
resourceProvider.RemoveOwner(Owner); provider.RemoveOwner(owner);
} }
_cache = null;
} }
(Owner as IStyleHost)?.StylesRemoved(ToReadOnlyList<IStyle>(items)); (owner as IStyleHost)?.StylesRemoved(ToReadOnlyList<IStyle>(items));
}
if (items.Count > 0)
{
cache = null;
}
}
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
throw new InvalidOperationException("Reset should not be called on Styles.");
} }
var currentOwner = Owner;
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Add(e.NewItems!); InternalAdd(e.NewItems!, currentOwner, ref _cache);
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Remove(e.OldItems!); InternalRemove(e.OldItems!, currentOwner, ref _cache);
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
Remove(e.OldItems!); InternalRemove(e.OldItems!, currentOwner, ref _cache);
Add(e.NewItems!); InternalAdd(e.NewItems!, currentOwner, ref _cache);
break; break;
case NotifyCollectionChangedAction.Reset:
throw new InvalidOperationException("Reset should not be called on Styles.");
} }
CollectionChanged?.Invoke(this, e); CollectionChanged?.Invoke(this, e);

2
src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs

@ -30,7 +30,7 @@ namespace Avalonia.Threading
/// <inheritdoc/> /// <inheritdoc/>
public override void Post(SendOrPostCallback d, object? state) public override void Post(SendOrPostCallback d, object? state)
{ {
Dispatcher.UIThread.Post(() => d(state), DispatcherPriority.Background); Dispatcher.UIThread.Post(d, state, DispatcherPriority.Background);
} }
/// <inheritdoc/> /// <inheritdoc/>

2
src/Avalonia.Base/Threading/Dispatcher.cs

@ -118,7 +118,7 @@ namespace Avalonia.Threading
} }
/// <inheritdoc/> /// <inheritdoc/>
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority = default) public void Post(SendOrPostCallback action, object? arg, DispatcherPriority priority = default)
{ {
_ = action ?? throw new ArgumentNullException(nameof(action)); _ = action ?? throw new ArgumentNullException(nameof(action));
_jobRunner.Post(action, arg, priority); _jobRunner.Post(action, arg, priority);

9
src/Avalonia.Base/Threading/IDispatcher.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Avalonia.Threading namespace Avalonia.Threading
@ -26,6 +27,14 @@ namespace Avalonia.Threading
/// <param name="priority">The priority with which to invoke the method.</param> /// <param name="priority">The priority with which to invoke the method.</param>
void Post(Action action, DispatcherPriority priority = default); void Post(Action action, DispatcherPriority priority = default);
/// <summary>
/// Posts an action that will be invoked on the dispatcher thread.
/// </summary>
/// <param name="action">The method.</param>
/// <param name="arg">The argument of method to call.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
void Post(SendOrPostCallback action, object? arg, DispatcherPriority priority = default);
/// <summary> /// <summary>
/// Invokes a action on the dispatcher thread. /// Invokes a action on the dispatcher thread.
/// </summary> /// </summary>

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

Loading…
Cancel
Save