diff --git a/.editorconfig b/.editorconfig
index 7051372383..bfeab8c84f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -138,30 +138,25 @@ space_within_single_line_array_initializer_braces = true
#Net Analyzer
dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed.
-# CS0649: Field 'field' is never assigned to, and will always have its default value 'value'
-dotnet_diagnostic.CS0649.severity = error
-
-# CS0162: Remove unreachable code
-dotnet_diagnostic.CS0162.severity = error
# CA1018: Mark attributes with AttributeUsageAttribute
-dotnet_diagnostic.CA1018.severity = error
+dotnet_diagnostic.CA1018.severity = warning
# CA1304: Specify CultureInfo
dotnet_diagnostic.CA1304.severity = warning
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
# CA1813: Avoid unsealed attributes
-dotnet_diagnostic.CA1813.severity = error
+dotnet_diagnostic.CA1813.severity = warning
# CA1815: Override equals and operator equals on value types
dotnet_diagnostic.CA1815.severity = warning
# CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers
-dotnet_diagnostic.CA1821.severity = error
+dotnet_diagnostic.CA1821.severity = warning
# CA1822: Mark members as static
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_code_quality.CA1822.api_surface = private, internal
# CA1823: Avoid unused private fields
-dotnet_diagnostic.CA1823.severity = error
+dotnet_diagnostic.CA1823.severity = warning
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
# CA1826: Use property instead of Linq Enumerable method
@@ -179,48 +174,48 @@ dotnet_diagnostic.CA1851.severity = warning
#CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
dotnet_diagnostic.CA1854.severity = warning
#CA2211:Non-constant fields should not be visible
-dotnet_diagnostic.CA2211.severity = error
+dotnet_diagnostic.CA2211.severity = warning
# Wrapping preferences
csharp_wrap_before_ternary_opsigns = false
# Avalonia DevAnalyzer preferences
-dotnet_diagnostic.AVADEV2001.severity = error
+dotnet_diagnostic.AVADEV2001.severity = warning
# Avalonia PublicAnalyzer preferences
-dotnet_diagnostic.AVP1000.severity = error
-dotnet_diagnostic.AVP1001.severity = error
-dotnet_diagnostic.AVP1002.severity = error
-dotnet_diagnostic.AVP1010.severity = error
-dotnet_diagnostic.AVP1011.severity = error
+dotnet_diagnostic.AVP1000.severity = warning
+dotnet_diagnostic.AVP1001.severity = warning
+dotnet_diagnostic.AVP1002.severity = warning
+dotnet_diagnostic.AVP1010.severity = warning
+dotnet_diagnostic.AVP1011.severity = warning
dotnet_diagnostic.AVP1012.severity = warning
-dotnet_diagnostic.AVP1013.severity = error
-dotnet_diagnostic.AVP1020.severity = error
-dotnet_diagnostic.AVP1021.severity = error
-dotnet_diagnostic.AVP1022.severity = error
-dotnet_diagnostic.AVP1030.severity = error
-dotnet_diagnostic.AVP1031.severity = error
-dotnet_diagnostic.AVP1032.severity = error
-dotnet_diagnostic.AVP1040.severity = error
-dotnet_diagnostic.AVA2001.severity = error
+dotnet_diagnostic.AVP1013.severity = warning
+dotnet_diagnostic.AVP1020.severity = warning
+dotnet_diagnostic.AVP1021.severity = warning
+dotnet_diagnostic.AVP1022.severity = warning
+dotnet_diagnostic.AVP1030.severity = warning
+dotnet_diagnostic.AVP1031.severity = warning
+dotnet_diagnostic.AVP1032.severity = warning
+dotnet_diagnostic.AVP1040.severity = warning
+dotnet_diagnostic.AVA2001.severity = warning
# Xaml files
[*.{xaml,axaml}]
indent_size = 2
# DuplicateSetterError
-avalonia_xaml_diagnostic.AVLN2203.severity = error
+avalonia_xaml_diagnostic.AVLN2203.severity = warning
# StyleInMergedDictionaries
-avalonia_xaml_diagnostic.AVLN2204.severity = error
+avalonia_xaml_diagnostic.AVLN2204.severity = warning
# RequiredTemplatePartMissing
-avalonia_xaml_diagnostic.AVLN2205.severity = error
+avalonia_xaml_diagnostic.AVLN2205.severity = warning
# OptionalTemplatePartMissing
avalonia_xaml_diagnostic.AVLN2206.severity = info
# TemplatePartWrongType
-avalonia_xaml_diagnostic.AVLN2207.severity = error
+avalonia_xaml_diagnostic.AVLN2207.severity = warning
# ItemContainerInsideTemplate
-avalonia_xaml_diagnostic.AVLN2208.severity = error
+avalonia_xaml_diagnostic.AVLN2208.severity = warning
# Obsolete
-avalonia_xaml_diagnostic.AVLN5001.severity = error
+avalonia_xaml_diagnostic.AVLN5001.severity = warning
# Xml project files
[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
diff --git a/Avalonia.sln b/Avalonia.sln
index 1083462dcc..06c3e051ac 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -106,7 +106,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\TargetFrameworks.props = build\TargetFrameworks.props
build\TrimmingEnable.props = build\TrimmingEnable.props
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
- build\WarnAsErrors.props = build\WarnAsErrors.props
build\XUnit.props = build\XUnit.props
EndProjectSection
EndProject
diff --git a/Directory.Build.props b/Directory.Build.props
index 4498f87dab..400198daf9 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,17 +1,18 @@
-
- $(MSBuildThisFileDirectory)build-intermediate/nuget
- $(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\$(AvsCurrentTargetFramework)\Avalonia.Designer.HostApp.dll
-
- false
- False
- 14.0
- true
- true
- true
- true
+ $(MSBuildThisFileDirectory)build-intermediate/nuget
+ $(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\$(AvsCurrentTargetFramework)\Avalonia.Designer.HostApp.dll
+
+ false
+ False
+ 14.0
+ $(AvnTreatWarningsAsErrors)
+ true
+ true
+ true
+ true
+ true
diff --git a/api/Avalonia.Headless.XUnit.nupkg.xml b/api/Avalonia.Headless.XUnit.nupkg.xml
new file mode 100644
index 0000000000..c87cf909fe
--- /dev/null
+++ b/api/Avalonia.Headless.XUnit.nupkg.xml
@@ -0,0 +1,76 @@
+
+
+
+
+ CP0001
+ T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkTypeDiscoverer
+ baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0001
+ T:Avalonia.Headless.XUnit.AvaloniaUIFactDiscoverer
+ baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0001
+ T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkTypeDiscoverer
+ baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0001
+ T:Avalonia.Headless.XUnit.AvaloniaUIFactDiscoverer
+ baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0002
+ M:Avalonia.Headless.XUnit.AvaloniaFactAttribute.#ctor
+ baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0002
+ M:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer.#ctor(Xunit.Abstractions.IMessageSink)
+ baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0002
+ M:Avalonia.Headless.XUnit.AvaloniaFactAttribute.#ctor
+ baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0002
+ M:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer.#ctor(Xunit.Abstractions.IMessageSink)
+ baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0007
+ T:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer
+ baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0007
+ T:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer
+ baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0008
+ T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkAttribute
+ baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll
+
+
+ CP0008
+ T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkAttribute
+ baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+ current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll
+
+
diff --git a/api/Avalonia.Win32.Interoperability.nupkg.xml b/api/Avalonia.Win32.Interoperability.nupkg.xml
index 33fc2ac062..3672bb9b99 100644
--- a/api/Avalonia.Win32.Interoperability.nupkg.xml
+++ b/api/Avalonia.Win32.Interoperability.nupkg.xml
@@ -1,4 +1,4 @@
-
+
@@ -37,4 +37,4 @@
baseline/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll
current/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll
-
\ No newline at end of file
+
diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml
index cab4bf5580..f8b5337574 100644
--- a/api/Avalonia.nupkg.xml
+++ b/api/Avalonia.nupkg.xml
@@ -1,995 +1,839 @@
-
+
CP0001
- T:Avalonia.Media.IGlyphTypeface
+ T:Avalonia.Controls.Primitives.IScrollable
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0001
- T:Avalonia.Media.IGlyphTypeface
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
-
-
- CP0002
- M:Avalonia.Media.FontManager.TryGetGlyphTypeface(Avalonia.Media.Typeface,Avalonia.Media.IGlyphTypeface@)
+ T:Avalonia.Media.Fonts.FontFamilyLoader
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.FontMetrics.get_DesignEmHeight
+ CP0001
+ T:Avalonia.Platform.IGeometryContext2
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(Avalonia.Media.IGlyphTypeface)
+ CP0001
+ T:Avalonia.Utilities.StringTokenizer
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.IO.Stream,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Controls.Primitives.IScrollable
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Media.Fonts.FontFamilyLoader
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Controls.Primitives.IScrollable
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Media.Fonts.FontFamilyLoader
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Platform.IGeometryContext2
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.Collections.Generic.IDictionary{Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface},Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Utilities.StringTokenizer
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Controls.Primitives.IScrollable
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
- CP0002
- M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ CP0001
+ T:Avalonia.Media.Fonts.FontFamilyLoader
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Height
+ F:Avalonia.Media.DrawingImage.ViewboxProperty
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Width
+ F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},System.Nullable{Avalonia.Point},System.Int32)
+ M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{System.UInt16},System.Nullable{Avalonia.Point},System.Int32)
+ M:Avalonia.Input.KeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphRun.get_GlyphTypeface
+ M:Avalonia.Input.TextInput.TextInputMethodClient.ShowInputPanel
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32)
+ M:Avalonia.Media.DrawingImage.get_Viewbox
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
+ M:Avalonia.Media.DrawingImage.set_Viewbox(System.Nullable{Avalonia.Rect})
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16})
+ M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32})
+ M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@)
+ M:Avalonia.Media.StreamGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@)
+ M:Avalonia.Media.StreamGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.ShapedBuffer.#ctor(System.ReadOnlyMemory{System.Char},System.Int32,Avalonia.Media.IGlyphTypeface,System.Double,System.SByte)
+ M:Avalonia.Media.StreamGeometryContext.LineTo(Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.ShapedBuffer.get_GlyphTypeface
+ M:Avalonia.Media.StreamGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextMetrics.#ctor(Avalonia.Media.IGlyphTypeface,System.Double)
+ M:Avalonia.Platform.IDrawingContextImplWithEffects.PushEffect(Avalonia.Media.IEffect)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Collections.Generic.IReadOnlyList{Avalonia.Media.FontFeature},System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double)
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double)
+ M:Avalonia.Platform.IGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextShaperOptions.get_Typeface
+ M:Avalonia.Platform.IGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Typeface.get_GlyphTypeface
+ M:Avalonia.Platform.IGeometryContext.LineTo(Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Platform.IGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Visuals.Platform.PathGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
+ M:Avalonia.Visuals.Platform.PathGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IGlyphRunImpl.get_GlyphTypeface
+ M:Avalonia.Visuals.Platform.PathGeometryContext.LineTo(Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.IGlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point)
+ M:Avalonia.Visuals.Platform.PathGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0002
- F:Avalonia.Controls.Documents.TextElement.LetterSpacingProperty
+ F:Avalonia.Controls.Documents.Inline.TextDecorationsProperty
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.Presenters.ContentPresenter.LetterSpacingProperty
+ F:Avalonia.Controls.TextBlock.LetterSpacingProperty
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.Primitives.TemplatedControl.LetterSpacingProperty
+ F:Avalonia.Controls.TextBox.LetterSpacingProperty
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.TextBlock.LetterSpacingProperty
+ M:Avalonia.Controls.Design.CreatePreviewWithControl(System.Object)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.get_LetterSpacing
+ M:Avalonia.Controls.Design.GetDataContext(Avalonia.Controls.Templates.IDataTemplate)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.GetLetterSpacing(Avalonia.Controls.Control)
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Controls.Templates.IDataTemplate)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.set_LetterSpacing(System.Double)
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Styling.IStyle)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.SetLetterSpacing(Avalonia.Controls.Control,System.Double)
+ M:Avalonia.Controls.Design.SetDataContext(Avalonia.Controls.Templates.IDataTemplate,System.Object)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Presenters.ContentPresenter.get_LetterSpacing
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.Control)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Presenters.ContentPresenter.set_LetterSpacing(System.Double)
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Primitives.TemplatedControl.get_LetterSpacing
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.ResourceDictionary,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Primitives.TemplatedControl.set_LetterSpacing(System.Double)
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.Control)
baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Height
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Width
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.get_GlyphCount
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Controls.Control,System.String)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16})
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.#ctor(System.Double,Avalonia.PixelRect,Avalonia.PixelRect,System.Boolean)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32})
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_Bounds(Avalonia.PixelRect)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_CurrentOrientation(Avalonia.Platform.ScreenOrientation)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_DisplayName(System.String)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_IsPrimary(System.Boolean)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_Scaling(System.Double)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_WorkingArea(Avalonia.PixelRect)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IGlyphRunImpl.get_GlyphTypeface
+ F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache
baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.FontManager.TryGetGlyphTypeface(Avalonia.Media.Typeface,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
-
-
- CP0002
- M:Avalonia.Media.FontMetrics.get_DesignEmHeight
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
-
-
- CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.IO.Stream,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)
+ baseline/Avalonia/lib/net6.0/Avalonia.Dialogs.dll
+ current/Avalonia/lib/net6.0/Avalonia.Dialogs.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@)
+ F:Avalonia.Media.DrawingImage.ViewboxProperty
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.Collections.Generic.IDictionary{Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface},Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Input.KeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Input.TextInput.TextInputMethodClient.ShowInputPanel
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Height
+ M:Avalonia.Media.DrawingImage.get_Viewbox
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Width
+ M:Avalonia.Media.DrawingImage.set_Viewbox(System.Nullable{Avalonia.Rect})
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},System.Nullable{Avalonia.Point},System.Int32)
+ M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{System.UInt16},System.Nullable{Avalonia.Point},System.Int32)
+ M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.GlyphRun.get_GlyphTypeface
+ M:Avalonia.Media.StreamGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.get_GlyphCount
+ M:Avalonia.Media.StreamGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32)
+ M:Avalonia.Media.StreamGeometryContext.LineTo(Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
+ M:Avalonia.Media.StreamGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16})
+ M:Avalonia.Platform.IDrawingContextImplWithEffects.PushEffect(Avalonia.Media.IEffect)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32})
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@)
+ M:Avalonia.Platform.IGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@)
+ M:Avalonia.Platform.IGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.ShapedBuffer.#ctor(System.ReadOnlyMemory{System.Char},System.Int32,Avalonia.Media.IGlyphTypeface,System.Double,System.SByte)
+ M:Avalonia.Platform.IGeometryContext.LineTo(Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.ShapedBuffer.get_GlyphTypeface
+ M:Avalonia.Platform.IGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextMetrics.#ctor(Avalonia.Media.IGlyphTypeface,System.Double)
+ M:Avalonia.Visuals.Platform.PathGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Collections.Generic.IReadOnlyList{Avalonia.Media.FontFeature},System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double)
+ M:Avalonia.Visuals.Platform.PathGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double)
+ M:Avalonia.Visuals.Platform.PathGeometryContext.LineTo(Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.TextFormatting.TextShaperOptions.get_Typeface
+ M:Avalonia.Visuals.Platform.PathGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.Typeface.get_GlyphTypeface
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ F:Avalonia.Controls.Documents.Inline.TextDecorationsProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ F:Avalonia.Controls.TextBlock.LetterSpacingProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ F:Avalonia.Controls.TextBox.LetterSpacingProperty
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.CreatePreviewWithControl(System.Object)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.GetDataContext(Avalonia.Controls.Templates.IDataTemplate)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IGlyphRunImpl.get_GlyphTypeface
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Controls.Templates.IDataTemplate)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.IGlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Controls.Design.GetPreviewWith(Avalonia.Styling.IStyle)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.Documents.TextElement.LetterSpacingProperty
+ M:Avalonia.Controls.Design.SetDataContext(Avalonia.Controls.Templates.IDataTemplate,System.Object)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.Presenters.ContentPresenter.LetterSpacingProperty
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.Control)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.Primitives.TemplatedControl.LetterSpacingProperty
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- F:Avalonia.Controls.TextBlock.LetterSpacingProperty
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.ResourceDictionary,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.get_LetterSpacing
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.Control)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.GetLetterSpacing(Avalonia.Controls.Control)
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Controls.Templates.IDataTemplate,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.set_LetterSpacing(System.Double)
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.Control)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Documents.TextElement.SetLetterSpacing(Avalonia.Controls.Control,System.Double)
+ M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.Styling.IStyle,Avalonia.Controls.ITemplate{Avalonia.Controls.Control})
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Presenters.ContentPresenter.get_LetterSpacing
+ M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Presenters.ContentPresenter.set_LetterSpacing(System.Double)
+ M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Controls.Control,System.String)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Primitives.TemplatedControl.get_LetterSpacing
+ M:Avalonia.Platform.Screen.#ctor(System.Double,Avalonia.PixelRect,Avalonia.PixelRect,System.Boolean)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Controls.Primitives.TemplatedControl.set_LetterSpacing(System.Double)
+ M:Avalonia.Platform.Screen.set_Bounds(Avalonia.PixelRect)
baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Height
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_CurrentOrientation(Avalonia.Platform.ScreenOrientation)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.GlyphMetrics.get_Width
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_DisplayName(System.String)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.get_GlyphCount
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_IsPrimary(System.Boolean)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_Scaling(System.Double)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Screen.set_WorkingArea(Avalonia.PixelRect)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16})
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)
+ baseline/Avalonia/lib/net8.0/Avalonia.Dialogs.dll
+ current/Avalonia/lib/net8.0/Avalonia.Dialogs.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32})
+ F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@)
+ M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@)
+ M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Dialogs.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Dialogs.dll
CP0002
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IDrawingContextImplWithEffects.PopEffect
+ baseline/netstandard2.0/Avalonia.Base.dll
+ target/netstandard2.0/Avalonia.Base.dll
CP0002
- M:Avalonia.Platform.IGlyphRunImpl.get_GlyphTypeface
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IDrawingContextImplWithEffects.PushEffect(Avalonia.Media.IEffect)
+ baseline/netstandard2.0/Avalonia.Base.dll
+ target/netstandard2.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.GlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@)
+ M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers,System.Nullable{Avalonia.Input.KeyDeviceType})
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Platform.IDrawingContextImpl.PopTextOptions
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@)
+ M:Avalonia.Platform.IDrawingContextImpl.PushTextOptions(Avalonia.Media.TextOptions)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@)
+ M:Avalonia.Platform.IDrawingContextImplWithEffects.PushEffect(System.Nullable{Avalonia.Rect},Avalonia.Media.IEffect)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@)
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Platform.IGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection,System.Boolean)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
+ M:Avalonia.Platform.IGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point,System.Boolean)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@)
+ M:Avalonia.Platform.IGeometryContext.LineTo(Avalonia.Point,System.Boolean)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@)
+ M:Avalonia.Platform.IGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point,System.Boolean)
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.GlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.GlyphTypeface)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.FaceNames
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Storage.IStorageProvider.SaveFilePickerWithResultAsync(Avalonia.Platform.Storage.FilePickerSaveOptions)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.FamilyNames
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
+ baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.PlatformTypeface
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
+ baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.SupportedFeatures
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
+ P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType
+ baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName
- baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
- current/Avalonia/lib/net10.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.FaceNames
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.FamilyNames
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.GlyphCount
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.PlatformTypeface
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.SupportedFeatures
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName
- baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
- current/Avalonia/lib/net6.0/Avalonia.Base.dll
-
-
- CP0006
- M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
- baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
-
-
- CP0006
- M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
- baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
-
-
- CP0006
- P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType
- baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll
+ M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers,System.Nullable{Avalonia.Input.KeyDeviceType})
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
@@ -1017,296 +861,296 @@
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.GlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@)
+ M:Avalonia.Platform.IDrawingContextImpl.PopTextOptions
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Platform.IDrawingContextImpl.PushTextOptions(Avalonia.Media.TextOptions)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@)
+ M:Avalonia.Platform.IDrawingContextImplWithEffects.PushEffect(System.Nullable{Avalonia.Rect},Avalonia.Media.IEffect)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@)
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@)
+ M:Avalonia.Platform.IGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection,System.Boolean)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@)
+ M:Avalonia.Platform.IGeometryContext.CubicBezierTo(Avalonia.Point,Avalonia.Point,Avalonia.Point,System.Boolean)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
+ M:Avalonia.Platform.IGeometryContext.LineTo(Avalonia.Point,System.Boolean)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@)
+ M:Avalonia.Platform.IGeometryContext.QuadraticBezierTo(Avalonia.Point,Avalonia.Point,System.Boolean)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@)
+ M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@)
+ M:Avalonia.Platform.Storage.IStorageProvider.SaveFilePickerWithResultAsync(Avalonia.Platform.Storage.FilePickerSaveOptions)
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
+ baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
+ baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
CP0006
- M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.GlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType
+ baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
CP0006
- M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.GlyphTypeface)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.FaceNames
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.FamilyNames
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.GlyphCount
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.Platform.Storage.IStorageProvider.SaveFilePickerWithResultAsync(Avalonia.Platform.Storage.FilePickerSaveOptions)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.PlatformTypeface
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.SupportedFeatures
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
CP0006
- P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface
- baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
- current/Avalonia/lib/net8.0/Avalonia.Base.dll
+ P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName
+ CP0008
+ T:Avalonia.Media.StreamGeometryContext
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
+
+
+ CP0008
+ T:Avalonia.Media.StreamGeometryContext
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
- baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
+ CP0009
+ T:Avalonia.Platform.Screen
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
- CP0006
- M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
- baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
+ CP0009
+ T:Avalonia.Platform.Screen
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
- CP0006
- P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType
- baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Count
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Count
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Platform.Screen.Equals(Avalonia.Platform.Screen)
+ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net10.0/Avalonia.Controls.dll
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Count
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Count
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)
+ baseline/Avalonia/lib/net6.0/Avalonia.Base.dll
+ current/Avalonia/lib/net6.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Count
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.FaceNames
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.FamilyNames
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Count
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.GlyphCount
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.PlatformTypeface
- baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ CP0012
+ M:Avalonia.Platform.Screen.Equals(Avalonia.Platform.Screen)
+ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll
+ current/Avalonia/lib/net8.0/Avalonia.Controls.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.SupportedFeatures
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Count
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName
+ CP0012
+ M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator
baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- CP0006
- M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
-
-
- CP0006
- M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)
- baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Count
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
- CP0006
- P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType
- baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
- current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll
+ CP0012
+ P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)
+ baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
+ current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll
-
\ No newline at end of file
+
diff --git a/build/AnalyzerProject.targets b/build/AnalyzerProject.targets
index c1b96ebe04..4a95cb306e 100644
--- a/build/AnalyzerProject.targets
+++ b/build/AnalyzerProject.targets
@@ -3,6 +3,7 @@
true
true
+ true
$(NoWarn);RS2008
diff --git a/build/NullableEnable.props b/build/NullableEnable.props
index ef62ecc50c..60b91b85a3 100644
--- a/build/NullableEnable.props
+++ b/build/NullableEnable.props
@@ -1,11 +1,7 @@
-
enable
- $(WarningsAsErrors);nullable
- $(NoWarn);nullable
+
+ $(NoWarn);nullable
diff --git a/build/TrimmingEnable.props b/build/TrimmingEnable.props
index 34b3e232b6..cf84ae67b4 100644
--- a/build/TrimmingEnable.props
+++ b/build/TrimmingEnable.props
@@ -1,28 +1,16 @@
-
+
false
true
false
true
-
-
-
true
+ $(TreatWarningsAsErrors)
-
- true
-
- $(WarningsAsErrors);IL2000;IL2001;IL2002;IL2003;IL2004;IL2005;IL2006;IL2007;IL2008;IL2009;IL2010;IL2011;IL2012;IL2013;IL2014;IL2015;IL2016;IL2017;IL2018;IL2019;IL2020;IL2021;IL2022;IL2023;IL2024;IL2025;IL2026;IL2027;IL2028;IL2029;IL2030;IL2031;IL2032;IL2033;IL2034;IL2035;IL2036;IL2037;IL2038;IL2039;IL2040;IL2041;IL2042;IL2043;IL2044;IL2045;IL2046;IL2047;IL2048;IL2049;IL2050;IL2051;IL2052;IL2053;IL2054;IL2055;IL2056;IL2057;IL2058;IL2059;IL2060;IL2061;IL2062;IL2063;IL2064;IL2065;IL2066;IL2067;IL2068;IL2069;IL2070;IL2071;IL2072;IL2073;IL2074;IL2075;IL2076;IL2077;IL2078;IL2079;IL2080;IL2081;IL2082;IL2083;IL2084;IL2085;IL2086;IL2087;IL2088;IL2089;IL2090;IL2091;IL2092;IL2093;IL2094;IL2095;IL2096;IL2097;IL2098;IL2099;IL2100;IL2101;IL2102;IL2103;IL2104;IL2105;IL2106;IL2107;IL2108;IL2109;IL2110;IL2111;IL2112;IL2113;IL2114;IL2115;IL2116;IL2117;IL2118;IL2119;IL2120;IL2121;IL2122;IL2123;IL2124;IL2125;IL2126;IL2127;IL2128;IL2129;IL2130;IL2131;IL2132;IL2133;IL2134;IL2135;IL2136;IL2137;IL2138;IL2139;IL2140;IL2141;IL2142;IL2143;IL2144;IL2145;IL2146;IL2147;IL2148;IL2149;IL2150;IL2151;IL2152;IL2153;IL2154;IL2155;IL2156;IL2157
-
- $(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056
-
-
-
- $(WarningsAsErrors);CA1420;CA1421
-
+
diff --git a/build/WarnAsErrors.props b/build/WarnAsErrors.props
deleted file mode 100644
index eaab7bd00c..0000000000
--- a/build/WarnAsErrors.props
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- $(WarningsNotAsErrors);CS0649
-
- $(WarningsNotAsErrors);CS0162
-
- $(WarningsNotAsErrors);CA2211
-
- $(WarningsNotAsErrors);CA1821
-
- $(WarningsNotAsErrors);CA1823
-
- $(WarningsNotAsErrors);AVLN2203
-
- $(WarningsNotAsErrors);AVLN2205
-
- $(WarningsNotAsErrors);AVLN2207
-
- $(WarningsNotAsErrors);AVLN2208
-
-
diff --git a/build/XUnit.props b/build/XUnit.props
index c2ccb1fa2c..5c63ed69db 100644
--- a/build/XUnit.props
+++ b/build/XUnit.props
@@ -1,14 +1,13 @@
-
+
+
-
-
-
-
+
$(MSBuildThisFileDirectory)\avalonia.snk
False
$(NoWarn);CS8002
+
diff --git a/docs/build.md b/docs/build.md
index cef5ed3e10..2285e56d01 100644
--- a/docs/build.md
+++ b/docs/build.md
@@ -71,7 +71,7 @@ And run tests:
Or if you need to create nuget packages as well (it will compile and run tests automatically):
`nuke --target Package --configuration Release`
-Alternatively, you can run nuke build direclty without installing Nuke global tool:
+Alternatively, you can run nuke build directly without installing Nuke global tool:
`dotnet run --project nukebuild/_build.csproj -- --configuration Debug`
# Linux/macOS
diff --git a/external/Numerge b/external/Numerge
index 9738c6121f..5530e1cbe9 160000
--- a/external/Numerge
+++ b/external/Numerge
@@ -1 +1 @@
-Subproject commit 9738c6121fdd143c78d3e25686a7e4e13c00f586
+Subproject commit 5530e1cbe9e105ff4ebc9da1f4af3253a8756754
diff --git a/native/Avalonia.Native/src/OSX/AvnAccessibility.h b/native/Avalonia.Native/src/OSX/AvnAccessibility.h
index 6658d8523e..4f8b50ecc5 100644
--- a/native/Avalonia.Native/src/OSX/AvnAccessibility.h
+++ b/native/Avalonia.Native/src/OSX/AvnAccessibility.h
@@ -7,7 +7,6 @@
@protocol AvnAccessibility
@required
- (void) raiseChildrenChanged;
-@optional
- (void) raiseFocusChanged;
- (void) raisePropertyChanged:(AvnAutomationProperty)property;
@end
diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm
index 6d49fc85e0..1e7c98cb3a 100644
--- a/native/Avalonia.Native/src/OSX/AvnWindow.mm
+++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm
@@ -656,5 +656,9 @@
NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification);
}
+- (void)raisePropertyChanged:(AvnAutomationProperty)property
+{
+}
+
@end
diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm
index 30e1f5ea00..5cd4edaa54 100644
--- a/native/Avalonia.Native/src/OSX/automation.mm
+++ b/native/Avalonia.Native/src/OSX/automation.mm
@@ -11,6 +11,7 @@
IAvnAutomationPeer* _peer;
AvnAutomationNode* _node;
NSMutableArray* _children;
+ NSArray* _attributeNames;
}
+ (NSAccessibilityElement *)acquire:(IAvnAutomationPeer *)peer
@@ -126,6 +127,7 @@
case AutomationHeaderItem: return NSAccessibilityButtonRole;
case AutomationTable: return NSAccessibilityTableRole;
case AutomationTitleBar: return NSAccessibilityGroupRole;
+ case AutomationExpander: return NSAccessibilityDisclosureTriangleRole;
// Treat unknown roles as generic group container items. Returning
// NSAccessibilityUnknownRole is also possible but makes the screen
// reader focus on the item instead of passing focus to child items.
@@ -165,6 +167,32 @@
return NSAccessibilityRoleDescription([self accessibilityRole], [self accessibilitySubrole]);
}
+// Note: Apple has deprecated this API, but it's still used to set attributes not supported by NSAccessibility
+- (NSArray *)accessibilityAttributeNames
+{
+ if (_attributeNames == nil)
+ {
+ _attributeNames = @[
+ @"AXARIALive", // kAXARIALiveAttribute
+ ];
+ }
+ return _attributeNames;
+}
+
+- (id)accessibilityAttributeValue:(NSAccessibilityAttributeName)attribute
+{
+ if ([attribute isEqualToString:@"AXARIALive" /* kAXARIALiveAttribute */])
+ {
+ switch (_peer->GetLiveSetting())
+ {
+ case LiveSettingPolite: return @"polite";
+ case LiveSettingAssertive: return @"assertive";
+ }
+ return nil;
+ }
+ return nil;
+}
+
- (NSString *)accessibilityIdentifier
{
return GetNSStringAndRelease(_peer->GetAutomationId());
@@ -420,8 +448,15 @@
@{ NSAccessibilityUIElementsKey: [changed allObjects]});
}
-- (void)raisePropertyChanged
+- (void)raisePropertyChanged:(AvnAutomationProperty)property
+{
+ if (property == AutomationPeer_Name && _peer->GetLiveSetting() != LiveSettingOff)
+ [self raiseLiveRegionChanged];
+}
+
+- (void)raiseLiveRegionChanged
{
+ NSAccessibilityPostNotification(self, @"AXLiveRegionChanged" /* kAXLiveRegionChangedNotification */);
}
- (void)setAccessibilityFocused:(BOOL)accessibilityFocused
diff --git a/nukebuild/.editorconfig b/nukebuild/.editorconfig
index c11849c8e9..d6009b3c0f 100644
--- a/nukebuild/.editorconfig
+++ b/nukebuild/.editorconfig
@@ -6,12 +6,3 @@ root = false
# C# files
[*.cs]
dotnet_style_require_accessibility_modifiers = never
-
-[{il-repack,Numerge}/**/*.cs]
-dotnet_diagnostic.CA1304.severity = none
-dotnet_diagnostic.CA1815.severity = none
-dotnet_diagnostic.CA1820.severity = none
-dotnet_diagnostic.CA1825.severity = none
-dotnet_diagnostic.CA1829.severity = none
-dotnet_diagnostic.CA1847.severity = none
-dotnet_diagnostic.SYSLIB0017.severity = none
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index 075715346d..c3ee103e73 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -4,11 +4,9 @@
false
False
- $(NoWarn);CS0649;CS0169;SYSLIB0011
+ $(NoWarn);CS0649;CA1847
1
$(AvsCurrentTargetFramework)
-
- true
diff --git a/packages/Avalonia/Avalonia.props b/packages/Avalonia/Avalonia.props
index 78656a1726..c36f495ea5 100644
--- a/packages/Avalonia/Avalonia.props
+++ b/packages/Avalonia/Avalonia.props
@@ -1,6 +1,6 @@
- $(MSBuildThisFileDirectory)\..\tools\$(AvsCurrentTargetFramework)\designer\Avalonia.Designer.HostApp.dll
+ $(MSBuildThisFileDirectory)\..\tools\net8.0\designer\Avalonia.Designer.HostApp.dll
$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll
$(UsedAvaloniaProducts);AvaloniaUI
true
diff --git a/samples/IntegrationTestApp/Pages/AutomationPage.axaml b/samples/IntegrationTestApp/Pages/AutomationPage.axaml
index dcc1ee479c..c02bc1baa6 100644
--- a/samples/IntegrationTestApp/Pages/AutomationPage.axaml
+++ b/samples/IntegrationTestApp/Pages/AutomationPage.axaml
@@ -22,5 +22,8 @@
Header None
+
+
+ This is an assertive live region.
diff --git a/samples/IntegrationTestApp/Pages/AutomationPage.axaml.cs b/samples/IntegrationTestApp/Pages/AutomationPage.axaml.cs
index f79000126c..7bf37c175f 100644
--- a/samples/IntegrationTestApp/Pages/AutomationPage.axaml.cs
+++ b/samples/IntegrationTestApp/Pages/AutomationPage.axaml.cs
@@ -1,4 +1,5 @@
using Avalonia.Controls;
+using Avalonia.Interactivity;
namespace IntegrationTestApp.Pages;
@@ -8,4 +9,9 @@ public partial class AutomationPage : UserControl
{
InitializeComponent();
}
+
+ private void OnButtonAddSomeText(object? sender, RoutedEventArgs? e)
+ {
+ textLiveRegion.Text += " Lorem ipsum.";
+ }
}
diff --git a/samples/TextTestApp/InteractiveLineControl.cs b/samples/TextTestApp/InteractiveLineControl.cs
index 362be52ac3..7af977f9a1 100644
--- a/samples/TextTestApp/InteractiveLineControl.cs
+++ b/samples/TextTestApp/InteractiveLineControl.cs
@@ -336,7 +336,7 @@ namespace TextTestApp
_textSource = new TextSource(this);
RenderOptions.SetEdgeMode(this, EdgeMode.Aliased);
- RenderOptions.SetTextRenderingMode(this, TextRenderingMode.SubpixelAntialias);
+ TextOptions.SetTextRenderingMode(this, TextRenderingMode.SubpixelAntialias);
}
private void InvalidateTextRunProperties()
diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs
index 665feb2e2b..86b96772ce 100644
--- a/src/Android/Avalonia.Android/AvaloniaView.cs
+++ b/src/Android/Avalonia.Android/AvaloniaView.cs
@@ -39,6 +39,7 @@ namespace Avalonia.Android
OnConfigurationChanged();
_view.InternalView.SurfaceWindowCreated += InternalView_SurfaceWindowCreated;
+ _view.InternalView.SurfaceWindowDestroyed += InternalView_SurfaceWindowDestroyed;
_accessHelper = new AvaloniaAccessHelper(this);
ViewCompat.SetAccessibilityDelegate(this, _accessHelper);
@@ -51,9 +52,18 @@ namespace Avalonia.Android
if (Visibility == ViewStates.Visible)
{
OnVisibilityChanged(true);
+
+ _root?.InvalidateMeasure();
+ Invalidate();
}
}
+ private void InternalView_SurfaceWindowDestroyed(object? sender, EventArgs e)
+ {
+ OnVisibilityChanged(false);
+ _surfaceCreated = false;
+ }
+
internal TopLevelImpl TopLevelImpl => _view;
internal TopLevel? TopLevel => _root;
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
index 4a6058e078..3cdda52764 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
@@ -18,6 +18,8 @@ namespace Avalonia.Android
private double _scaling = 1;
public event EventHandler? SurfaceWindowCreated;
+ public event EventHandler? SurfaceWindowDestroyed;
+
public PixelSize Size => _size;
public double Scaling => _scaling;
@@ -61,6 +63,7 @@ namespace Avalonia.Android
.Log(this, "InvalidationAwareSurfaceView Destroyed");
ReleaseNativeWindowHandle();
_size = new PixelSize(1, 1);
+ SurfaceWindowDestroyed?.Invoke(this, EventArgs.Empty);
}
public virtual void SurfaceRedrawNeeded(ISurfaceHolder holder)
diff --git a/src/Avalonia.Base/Controls/IInternalScroller.cs b/src/Avalonia.Base/Controls/IInternalScroller.cs
deleted file mode 100644
index 226626731b..0000000000
--- a/src/Avalonia.Base/Controls/IInternalScroller.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Runtime.CompilerServices;
-
-namespace Avalonia.Controls.Primitives;
-
-// TODO12: Integrate with existing IScrollable interface, breaking change
-internal interface IInternalScroller
-{
- bool CanHorizontallyScroll { get; }
-
- bool CanVerticallyScroll { get; }
-}
diff --git a/src/Avalonia.Controls/IScrollable.cs b/src/Avalonia.Base/Controls/Primitives/IScrollable.cs
similarity index 63%
rename from src/Avalonia.Controls/IScrollable.cs
rename to src/Avalonia.Base/Controls/Primitives/IScrollable.cs
index 680088290c..ceaaf38c05 100644
--- a/src/Avalonia.Controls/IScrollable.cs
+++ b/src/Avalonia.Base/Controls/Primitives/IScrollable.cs
@@ -19,5 +19,15 @@ namespace Avalonia.Controls.Primitives
/// Gets the size of the viewport, in logical units.
///
Size Viewport { get; }
+
+ ///
+ /// Gets a value indicating whether the content can be scrolled horizontally.
+ ///
+ bool CanHorizontallyScroll { get; }
+
+ ///
+ /// Gets a value indicating whether the content can be scrolled horizontally.
+ ///
+ bool CanVerticallyScroll { get; }
}
}
diff --git a/src/Avalonia.Base/Data/CompiledBinding.cs b/src/Avalonia.Base/Data/CompiledBinding.cs
new file mode 100644
index 0000000000..764b04957e
--- /dev/null
+++ b/src/Avalonia.Base/Data/CompiledBinding.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using Avalonia.Controls;
+using Avalonia.Data.Converters;
+using Avalonia.Data.Core;
+using Avalonia.Data.Core.ExpressionNodes;
+using Avalonia.Data.Core.Parsers;
+
+namespace Avalonia.Data;
+
+///
+/// A binding which does not use reflection to access members.
+///
+public class CompiledBinding : BindingBase
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CompiledBinding() { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The binding path.
+ public CompiledBinding(CompiledBindingPath path) => Path = path;
+
+ ///
+ /// Gets or sets the amount of time, in milliseconds, to wait before updating the binding
+ /// source after the value on the target changes.
+ ///
+ ///
+ /// There is no delay when the source is updated via
+ /// or . Nor is there a delay when
+ /// is active and a new source object is provided.
+ ///
+ public int Delay { get; set; }
+
+ ///
+ /// Gets or sets the to use.
+ ///
+ public IValueConverter? Converter { get; set; }
+
+ ///
+ /// Gets or sets the culture in which to evaluate the converter.
+ ///
+ /// The default value is null.
+ ///
+ /// If this property is not set then will be used.
+ ///
+ [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
+ public CultureInfo? ConverterCulture { get; set; }
+
+ ///
+ /// Gets or sets a parameter to pass to .
+ ///
+ public object? ConverterParameter { get; set; }
+
+ ///
+ /// Gets or sets the value to use when the binding is unable to produce a value.
+ ///
+ public object? FallbackValue { get; set; } = AvaloniaProperty.UnsetValue;
+
+ ///
+ /// Gets or sets the binding mode.
+ ///
+ public BindingMode Mode { get; set; }
+
+ ///
+ /// Gets or sets the binding path.
+ ///
+ public CompiledBindingPath? Path { get; set; }
+
+ ///
+ /// Gets or sets the binding priority.
+ ///
+ public BindingPriority Priority { get; set; }
+
+ ///
+ /// Gets or sets the source for the binding.
+ ///
+ public object? Source { get; set; } = AvaloniaProperty.UnsetValue;
+
+ ///
+ /// Gets or sets the string format.
+ ///
+ public string? StringFormat { get; set; }
+
+ ///
+ /// Gets or sets the value to use when the binding result is null.
+ ///
+ public object? TargetNullValue { get; set; } = AvaloniaProperty.UnsetValue;
+
+ ///
+ /// Gets or sets a value that determines the timing of binding source updates for
+ /// and bindings.
+ ///
+ public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
+
+ internal WeakReference? DefaultAnchor { get; set; }
+ internal WeakReference? NameScope { get; set; }
+
+ internal override BindingExpressionBase CreateInstance(
+ AvaloniaObject target,
+ AvaloniaProperty? targetProperty,
+ object? anchor)
+ {
+ var enableDataValidation = targetProperty?.GetMetadata(target).EnableDataValidation ?? false;
+ var nodes = new List();
+ var isRooted = false;
+
+ Path?.BuildExpression(nodes, out isRooted);
+
+ // If the binding isn't rooted (i.e. doesn't have a Source or start with $parent, $self,
+ // #elementName etc.) then we need to add a data context source node.
+ if (Source == AvaloniaProperty.UnsetValue && !isRooted)
+ nodes.Insert(0, ExpressionNodeFactory.CreateDataContext(targetProperty));
+
+ // If the first node is an ISourceNode then allow it to select the source; otherwise
+ // use the binding source if specified, falling back to the target.
+ var source = nodes?.Count > 0 && nodes[0] is SourceNode sn
+ ? sn.SelectSource(Source, target, anchor ?? DefaultAnchor?.Target)
+ : Source != AvaloniaProperty.UnsetValue ? Source : target;
+
+ var (mode, trigger) = ResolveDefaultsFromMetadata(target, targetProperty);
+
+ return new BindingExpression(
+ source,
+ nodes,
+ FallbackValue,
+ delay: TimeSpan.FromMilliseconds(Delay),
+ converter: Converter,
+ converterCulture: ConverterCulture,
+ converterParameter: ConverterParameter,
+ enableDataValidation: enableDataValidation,
+ mode: mode,
+ priority: Priority,
+ stringFormat: StringFormat,
+ targetNullValue: TargetNullValue,
+ targetProperty: targetProperty,
+ targetTypeConverter: TargetTypeConverter.GetDefaultConverter(),
+ updateSourceTrigger: trigger);
+ }
+
+ private (BindingMode, UpdateSourceTrigger) ResolveDefaultsFromMetadata(
+ AvaloniaObject target,
+ AvaloniaProperty? targetProperty)
+ {
+ var mode = Mode;
+ var trigger = UpdateSourceTrigger == UpdateSourceTrigger.Default ?
+ UpdateSourceTrigger.PropertyChanged : UpdateSourceTrigger;
+
+ if (mode == BindingMode.Default)
+ {
+ if (targetProperty?.GetMetadata(target) is { } metadata)
+ mode = metadata.DefaultBindingMode;
+ else
+ mode = BindingMode.OneWay;
+ }
+
+ return (mode, trigger);
+ }
+}
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs b/src/Avalonia.Base/Data/CompiledBindingPath.cs
similarity index 92%
rename from src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
rename to src/Avalonia.Base/Data/CompiledBindingPath.cs
index 20e9c6e886..aea320702e 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
+++ b/src/Avalonia.Base/Data/CompiledBindingPath.cs
@@ -4,10 +4,10 @@ using System.Reflection;
using Avalonia.Controls;
using Avalonia.Data.Core;
using Avalonia.Data.Core.ExpressionNodes;
+using Avalonia.Data.Core.Parsers;
using Avalonia.Data.Core.Plugins;
-using Avalonia.Markup.Parsers;
-namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
+namespace Avalonia.Data
{
public class CompiledBindingPath
{
@@ -96,21 +96,17 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
///
public override string ToString()
- => string.Concat((IEnumerable) _elements);
+ => string.Concat((IEnumerable)_elements);
}
public class CompiledBindingPathBuilder
{
- private readonly int _apiVersion;
private readonly List _elements = new();
public CompiledBindingPathBuilder()
{
}
- // TODO12: Remove this constructor. apiVersion is only needed for compatibility with
- // versions of Avalonia which used $self.Property() for building TemplatedParent bindings.
- public CompiledBindingPathBuilder(int apiVersion) => _apiVersion = apiVersion;
public CompiledBindingPathBuilder Not()
{
@@ -120,22 +116,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public CompiledBindingPathBuilder Property(IPropertyInfo info, Func, IPropertyInfo, IPropertyAccessor> accessorFactory)
{
- // Older versions of Avalonia used $self.Property() for building TemplatedParent bindings.
- // Try to detect this and upgrade to using a TemplatedParentPathElement so that logging works
- // correctly.
- if (_apiVersion == 0 &&
- info.Name == "TemplatedParent" &&
- _elements.Count >= 1 &&
- _elements[_elements.Count - 1] is SelfPathElement)
- {
- _elements.Add(new TemplatedParentPathElement());
- }
- else
- {
- return Property(info, accessorFactory, acceptsNull: false);
- }
-
- return this;
+ return Property(info, accessorFactory, acceptsNull: false);
}
public CompiledBindingPathBuilder Property(
@@ -285,7 +266,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public MethodInfo Method { get; }
public Type DelegateType { get; }
-
+
public bool AcceptsNull { get; }
}
diff --git a/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs b/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs
index 6ab0031f31..e82bb5d216 100644
--- a/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs
+++ b/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs
@@ -24,9 +24,11 @@ namespace Avalonia.Input
/// The current element.
/// The direction to move.
/// Any key modifiers active at the time of focus.
- void Move(
+ /// The device type used to move the focus.
+ bool Move(
IInputElement element,
NavigationDirection direction,
- KeyModifiers keyModifiers = KeyModifiers.None);
+ KeyModifiers keyModifiers = KeyModifiers.None,
+ KeyDeviceType? deviceType = null);
}
}
diff --git a/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs b/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
index 3444a88aba..e5e7eb0699 100644
--- a/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
+++ b/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
@@ -98,22 +98,12 @@ namespace Avalonia.Input
return result;
}
- ///
- /// Moves the focus in the specified direction.
- ///
- /// The current element.
- /// The direction to move.
- /// Any key modifiers active at the time of focus.
- public void Move(
+ ///
+ public bool Move(
IInputElement? element,
NavigationDirection direction,
- KeyModifiers keyModifiers = KeyModifiers.None)
- {
- MovePrivate(element, direction, keyModifiers, null);
- }
-
- // TODO12: remove MovePrivate, and make Move return boolean. Or even remove whole KeyboardNavigationHandler.
- private bool MovePrivate(IInputElement? element, NavigationDirection direction, KeyModifiers keyModifiers, KeyDeviceType? deviceType)
+ KeyModifiers keyModifiers = KeyModifiers.None,
+ KeyDeviceType? deviceType = null)
{
var next = GetNextPrivate(element, _owner, direction, deviceType);
@@ -140,7 +130,7 @@ namespace Avalonia.Input
var current = FocusManager.GetFocusManager(e.Source as IInputElement)?.GetFocusedElement();
var direction = (e.KeyModifiers & KeyModifiers.Shift) == 0 ?
NavigationDirection.Next : NavigationDirection.Previous;
- e.Handled = MovePrivate(current, direction, e.KeyModifiers, e.KeyDeviceType);
+ e.Handled = Move(current, direction, e.KeyModifiers, e.KeyDeviceType);
}
else if (e.Key is Key.Left or Key.Right or Key.Up or Key.Down)
{
@@ -153,7 +143,7 @@ namespace Avalonia.Input
Key.Down => NavigationDirection.Down,
_ => throw new ArgumentOutOfRangeException()
};
- e.Handled = MovePrivate(current, direction, e.KeyModifiers, e.KeyDeviceType);
+ e.Handled = Move(current, direction, e.KeyModifiers, e.KeyDeviceType);
}
}
diff --git a/src/Avalonia.Base/Input/Navigation/XYFocus.FindElements.cs b/src/Avalonia.Base/Input/Navigation/XYFocus.FindElements.cs
index a4eea7d88b..0f529142ca 100644
--- a/src/Avalonia.Base/Input/Navigation/XYFocus.FindElements.cs
+++ b/src/Avalonia.Base/Input/Navigation/XYFocus.FindElements.cs
@@ -78,7 +78,7 @@ public partial class XYFocus
return false;
}
- var closestScroller = candidate.FindAncestorOfType(true);
+ var closestScroller = candidate.FindAncestorOfType(true);
return ReferenceEquals(closestScroller, activeScroller);
}
@@ -93,7 +93,7 @@ public partial class XYFocus
var parent = activeScroller.Parent;
while (parent != null)
{
- if (parent is IInternalScroller and Visual visual
+ if (parent is IScrollable and Visual visual
&& visual.IsVisualAncestorOf(candidate))
{
return true;
diff --git a/src/Avalonia.Base/Input/Navigation/XYFocus.Impl.cs b/src/Avalonia.Base/Input/Navigation/XYFocus.Impl.cs
index 20267f4c0c..929d92a650 100644
--- a/src/Avalonia.Base/Input/Navigation/XYFocus.Impl.cs
+++ b/src/Avalonia.Base/Input/Navigation/XYFocus.Impl.cs
@@ -415,7 +415,7 @@ public partial class XYFocus
while (parent != null)
{
var element = parent;
- if (element is IInternalScroller scrollable)
+ if (element is IScrollable scrollable)
{
var isHorizontallyScrollable = scrollable.CanHorizontallyScroll;
var isVerticallyScrollable = scrollable.CanVerticallyScroll;
diff --git a/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs b/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs
index 7f9870315b..36e14cd3fd 100644
--- a/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs
+++ b/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs
@@ -82,13 +82,6 @@ namespace Avalonia.Input.TextInput
{
SetPreeditText(preeditText);
}
-
- //TODO12: remove
- [Obsolete]
- public virtual void ShowInputPanel()
- {
- RaiseInputPaneActivationRequested();
- }
protected virtual void RaiseTextViewVisualChanged()
{
diff --git a/src/Avalonia.Base/Media/BaselinePixelAlignment.cs b/src/Avalonia.Base/Media/BaselinePixelAlignment.cs
new file mode 100644
index 0000000000..37bd48c480
--- /dev/null
+++ b/src/Avalonia.Base/Media/BaselinePixelAlignment.cs
@@ -0,0 +1,26 @@
+namespace Avalonia.Media
+{
+ ///
+ /// Specifies the baseline pixel alignment options for rendering text or graphics.
+ ///
+ /// Use this enumeration to control whether the baseline of rendered content is aligned to the
+ /// pixel grid, which can affect visual crispness and positioning. The value may influence rendering quality,
+ /// especially at small font sizes or when precise alignment is required.
+ public enum BaselinePixelAlignment : byte
+ {
+ ///
+ /// The baseline pixel alignment is unspecified.
+ ///
+ Unspecified,
+
+ ///
+ /// The baseline is aligned to the pixel grid.
+ ///
+ Aligned,
+
+ ///
+ /// The baseline is not aligned to the pixel grid.
+ ///
+ Unaligned
+ }
+}
diff --git a/src/Avalonia.Base/Media/DrawingContext.cs b/src/Avalonia.Base/Media/DrawingContext.cs
index bd2c43878d..0f73e4af98 100644
--- a/src/Avalonia.Base/Media/DrawingContext.cs
+++ b/src/Avalonia.Base/Media/DrawingContext.cs
@@ -284,7 +284,8 @@ namespace Avalonia.Media
Clip,
GeometryClip,
OpacityMask,
- RenderOptions
+ RenderOptions,
+ TextOptions
}
public RestoreState(DrawingContext context, PushedStateType type)
@@ -311,6 +312,8 @@ namespace Avalonia.Media
_context.PopOpacityMaskCore();
else if (_type == PushedStateType.RenderOptions)
_context.PopRenderOptionsCore();
+ else if (_type == PushedStateType.TextOptions)
+ _context.PopTextOptionsCore();
}
}
@@ -417,6 +420,20 @@ namespace Avalonia.Media
}
protected abstract void PushRenderOptionsCore(RenderOptions renderOptions);
+ ///
+ /// Pushes text options for the drawing context.
+ ///
+ /// The text options.
+ /// A disposable to undo the text options.
+ public PushedState PushTextOptions(TextOptions textOptions)
+ {
+ PushTextOptionsCore(textOptions);
+ _states ??= StateStackPool.Get();
+ _states.Push(new RestoreState(this, RestoreState.PushedStateType.TextOptions));
+ return new PushedState(this);
+ }
+ protected abstract void PushTextOptionsCore(TextOptions textOptions);
+
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushPreTransform(Matrix matrix) => PushTransform(matrix);
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
@@ -433,6 +450,7 @@ namespace Avalonia.Media
protected abstract void PopOpacityMaskCore();
protected abstract void PopTransformCore();
protected abstract void PopRenderOptionsCore();
+ protected abstract void PopTextOptionsCore();
private static bool PenIsVisible(IPen? pen)
{
diff --git a/src/Avalonia.Base/Media/DrawingGroup.cs b/src/Avalonia.Base/Media/DrawingGroup.cs
index 7299bff850..75921196c0 100644
--- a/src/Avalonia.Base/Media/DrawingGroup.cs
+++ b/src/Avalonia.Base/Media/DrawingGroup.cs
@@ -54,6 +54,7 @@ namespace Avalonia.Media
}
internal RenderOptions? RenderOptions { get; set; }
+ internal TextOptions? TextOptions { get; set; }
///
/// Gets or sets the collection that contains the child geometries.
@@ -78,6 +79,7 @@ namespace Avalonia.Media
using (ClipGeometry != null ? context.PushGeometryClip(ClipGeometry) : default)
using (OpacityMask != null ? context.PushOpacityMask(OpacityMask, bounds) : default)
using (RenderOptions != null ? context.PushRenderOptions(RenderOptions.Value) : default)
+ using (TextOptions != null ? context.PushTextOptions(TextOptions.Value) : default)
{
foreach (var drawing in Children)
{
@@ -325,6 +327,15 @@ namespace Avalonia.Media
drawingGroup.RenderOptions = renderOptions;
}
+ protected override void PushTextOptionsCore(TextOptions textOptions)
+ {
+ // Instantiate a new drawing group and set it as the _currentDrawingGroup
+ var drawingGroup = PushNewDrawingGroup();
+
+ // Set the text options on the new DrawingGroup
+ drawingGroup.TextOptions = textOptions;
+ }
+
protected override void PopClipCore() => Pop();
protected override void PopGeometryClipCore() => Pop();
@@ -337,6 +348,8 @@ namespace Avalonia.Media
protected override void PopRenderOptionsCore() => Pop();
+ protected override void PopTextOptionsCore() => Pop();
+
///
/// Creates a new DrawingGroup for a Push* call by setting the
/// _currentDrawingGroup to a newly instantiated DrawingGroup,
diff --git a/src/Avalonia.Base/Media/PlatformDrawingContext.cs b/src/Avalonia.Base/Media/PlatformDrawingContext.cs
index 312cae2c52..12eef33a6d 100644
--- a/src/Avalonia.Base/Media/PlatformDrawingContext.cs
+++ b/src/Avalonia.Base/Media/PlatformDrawingContext.cs
@@ -85,6 +85,8 @@ internal sealed class PlatformDrawingContext : DrawingContext
}
protected override void PushRenderOptionsCore(RenderOptions renderOptions) => _impl.PushRenderOptions(renderOptions);
+
+ protected override void PushTextOptionsCore(TextOptions textOptions) => _impl.PushTextOptions(textOptions);
protected override void PopClipCore() => _impl.PopClip();
@@ -99,6 +101,8 @@ internal sealed class PlatformDrawingContext : DrawingContext
(_transforms ?? throw new ObjectDisposedException(nameof(PlatformDrawingContext))).Pop();
protected override void PopRenderOptionsCore() => _impl.PopRenderOptions();
+
+ protected override void PopTextOptionsCore() => _impl.PopTextOptions();
protected override void DisposeCore()
{
diff --git a/src/Avalonia.Base/Media/RenderOptions.cs b/src/Avalonia.Base/Media/RenderOptions.cs
index 1ac2520919..0bde05418c 100644
--- a/src/Avalonia.Base/Media/RenderOptions.cs
+++ b/src/Avalonia.Base/Media/RenderOptions.cs
@@ -1,13 +1,48 @@
-using Avalonia.Media.Imaging;
+using System;
+using Avalonia.Media.Imaging;
namespace Avalonia.Media
{
+ ///
+ /// Provides a set of options that control rendering behavior for visuals, including text rendering, bitmap
+ /// interpolation, edge rendering, blending, and opacity handling.
+ ///
+ /// Use this structure to specify rendering preferences for visual elements. Each property
+ /// corresponds to a specific aspect of rendering, allowing fine-grained control over how content is displayed.
+ /// These options can be applied to visuals to influence quality, performance, and visual effects. When merging two
+ /// instances, unspecified values are inherited from the other instance, enabling layered configuration.
public readonly record struct RenderOptions
{
+ ///
+ /// Gets the text rendering mode used to control how text glyphs are rendered.
+ ///
+ [Obsolete("TextRenderingMode is obsolete. Use TextOptions.TextRenderingMode instead.")]
+ public TextRenderingMode TextRenderingMode { get; init; }
+
+ ///
+ /// Gets the interpolation mode used when rendering bitmap images.
+ ///
+ /// The interpolation mode determines how bitmap images are scaled or transformed during
+ /// rendering. Selecting an appropriate mode can affect image quality and performance.
+ ///
public BitmapInterpolationMode BitmapInterpolationMode { get; init; }
+
+ ///
+ /// Gets the edge rendering mode used for drawing operations.
+ ///
public EdgeMode EdgeMode { get; init; }
- public TextRenderingMode TextRenderingMode { get; init; }
+
+ ///
+ /// Gets the blending mode used when rendering bitmap images.
+ ///
+ /// The blending mode determines how bitmap pixels are composited with the background or
+ /// other images. Select an appropriate mode based on the desired visual effect, such as transparency or
+ /// additive blending.
public BitmapBlendingMode BitmapBlendingMode { get; init; }
+
+ ///
+ /// Gets a value indicating whether full opacity handling is required for the associated content.
+ ///
public bool? RequiresFullOpacityHandling { get; init; }
///
@@ -75,6 +110,7 @@ namespace Avalonia.Media
///
/// The control.
/// The value.
+ [Obsolete("TextRenderingMode is obsolete. Use TextOptions.TextRenderingMode instead.")]
public static TextRenderingMode GetTextRenderingMode(Visual visual)
{
return visual.RenderOptions.TextRenderingMode;
@@ -85,6 +121,7 @@ namespace Avalonia.Media
///
/// The control.
/// The value.
+ [Obsolete("TextRenderingMode is obsolete. Use TextOptions.TextRenderingMode instead.")]
public static void SetTextRenderingMode(Visual visual, TextRenderingMode value)
{
visual.RenderOptions = visual.RenderOptions with { TextRenderingMode = value };
@@ -126,11 +163,15 @@ namespace Avalonia.Media
edgeMode = other.EdgeMode;
}
+#pragma warning disable CS0618
var textRenderingMode = TextRenderingMode;
+#pragma warning restore CS0618
if (textRenderingMode == TextRenderingMode.Unspecified)
{
+#pragma warning disable CS0618
textRenderingMode = other.TextRenderingMode;
+#pragma warning disable CS0618
}
var bitmapBlendingMode = BitmapBlendingMode;
diff --git a/src/Avalonia.Base/Media/StreamGeometryContext.cs b/src/Avalonia.Base/Media/StreamGeometryContext.cs
index c8072564b1..05c17f2b4d 100644
--- a/src/Avalonia.Base/Media/StreamGeometryContext.cs
+++ b/src/Avalonia.Base/Media/StreamGeometryContext.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Media
/// of is obtained by calling
/// .
///
- public class StreamGeometryContext : IGeometryContext, IGeometryContext2
+ public class StreamGeometryContext : IGeometryContext
{
private readonly IStreamGeometryContextImpl _impl;
@@ -34,15 +34,13 @@ namespace Avalonia.Media
_impl.SetFillRule(fillRule);
}
-
- ///
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
+ ///
+ public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked = true)
{
- _impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection);
+ _impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection, isStroked);
_currentPoint = point;
}
-
///
/// Draws an arc to the specified point using polylines, quadratic or cubic Bezier curves
/// Significantly more precise when drawing elliptic arcs with extreme width:height ratios.
@@ -59,34 +57,32 @@ namespace Avalonia.Media
PreciseEllipticArcHelper.ArcTo(this, _currentPoint, point, size, rotationAngle, isLargeArc, sweepDirection);
}
-
///
- public void BeginFigure(Point startPoint, bool isFilled)
+ public void BeginFigure(Point startPoint, bool isFilled = true)
{
_impl.BeginFigure(startPoint, isFilled);
_currentPoint = startPoint;
}
///
- public void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint)
+ public void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint, bool isStroked = true)
{
- _impl.CubicBezierTo(controlPoint1, controlPoint2, endPoint);
+ _impl.CubicBezierTo(controlPoint1, controlPoint2, endPoint, isStroked);
_currentPoint = endPoint;
}
///
- public void QuadraticBezierTo(Point controlPoint , Point endPoint)
+ public void QuadraticBezierTo(Point controlPoint, Point endPoint, bool isStroked = true)
{
- _impl.QuadraticBezierTo(controlPoint , endPoint);
+ _impl.QuadraticBezierTo(controlPoint, endPoint, isStroked);
_currentPoint = endPoint;
}
-
///
- public void LineTo(Point endPoint)
+ public void LineTo(Point point, bool isStroked = true)
{
- _impl.LineTo(endPoint);
- _currentPoint = endPoint;
+ _impl.LineTo(point, isStroked);
+ _currentPoint = point;
}
///
@@ -102,46 +98,5 @@ namespace Avalonia.Media
{
_impl.Dispose();
}
-
- ///
- public void LineTo(Point point, bool isStroked)
- {
- if (_impl is IGeometryContext2 context2)
- context2.LineTo(point, isStroked);
- else
- _impl.LineTo(point);
-
- _currentPoint = point;
- }
-
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked)
- {
- if (_impl is IGeometryContext2 context2)
- context2.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection, isStroked);
- else
- _impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection);
-
- _currentPoint = point;
- }
-
- public void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint, bool isStroked)
- {
- if (_impl is IGeometryContext2 context2)
- context2.CubicBezierTo(controlPoint1, controlPoint2, endPoint, isStroked);
- else
- _impl.CubicBezierTo(controlPoint1, controlPoint2, endPoint);
-
- _currentPoint = endPoint;
- }
-
- public void QuadraticBezierTo(Point controlPoint, Point endPoint, bool isStroked)
- {
- if (_impl is IGeometryContext2 context2)
- context2.QuadraticBezierTo(controlPoint, endPoint, isStroked);
- else
- _impl.QuadraticBezierTo(controlPoint, endPoint);
-
- _currentPoint = endPoint;
- }
}
}
diff --git a/src/Avalonia.Base/Media/TextHintingMode.cs b/src/Avalonia.Base/Media/TextHintingMode.cs
new file mode 100644
index 0000000000..0095bf04e9
--- /dev/null
+++ b/src/Avalonia.Base/Media/TextHintingMode.cs
@@ -0,0 +1,31 @@
+namespace Avalonia.Media
+{
+ ///
+ /// Specifies the level of hinting applied to text glyphs during rendering.
+ /// Text hinting adjusts glyph outlines to improve readability and crispness,
+ /// especially at small font sizes or low DPI. This enum controls the amount
+ /// of grid-fitting and outline adjustment performed.
+ ///
+ public enum TextHintingMode : byte
+ {
+ ///
+ /// Hinting mode is not explicitly specified. The default will be used.
+ ///
+ Unspecified,
+
+ ///
+ /// No hinting, outlines are scaled only.
+ ///
+ None,
+
+ ///
+ /// Minimal hinting, preserves glyph shape.
+ ///
+ Light,
+
+ ///
+ /// Aggressive grid-fitting, maximum crispness at low DPI.
+ ///
+ Strong
+ }
+}
diff --git a/src/Avalonia.Base/Media/TextOptions.cs b/src/Avalonia.Base/Media/TextOptions.cs
new file mode 100644
index 0000000000..d8d33b5f16
--- /dev/null
+++ b/src/Avalonia.Base/Media/TextOptions.cs
@@ -0,0 +1,136 @@
+namespace Avalonia.Media
+{
+ ///
+ /// Provides options for controlling text rendering behavior, including rendering mode, hinting mode, and baseline
+ /// pixel alignment. Used to configure how text appears within visual elements.
+ ///
+ /// TextOptions encapsulates settings that influence the clarity, sharpness, and positioning of
+ /// rendered text. These options can be applied to visual elements to customize text appearance for different
+ /// display scenarios, such as optimizing for readability at small font sizes or ensuring pixel-perfect alignment.
+ /// The struct supports merging with other instances to inherit unspecified values, and exposes attached properties
+ /// for use with visuals.
+ public readonly record struct TextOptions
+ {
+ ///
+ /// Gets the text rendering mode used to control how text glyphs are rendered.
+ ///
+ public TextRenderingMode TextRenderingMode { get; init; }
+
+ ///
+ /// Gets the text rendering hinting mode used to optimize the display of text.
+ ///
+ /// The hinting mode determines how text is rendered to improve clarity and readability,
+ /// especially at small font sizes. Changing this value may affect the appearance of text depending on the
+ /// rendering engine and display device.
+ public TextHintingMode TextHintingMode { get; init; }
+
+ ///
+ /// Gets a value indicating whether the text baseline should be aligned to the pixel grid.
+ ///
+ ///
+ /// When enabled, the vertical position of the text baseline is snapped to whole pixel boundaries.
+ /// This ensures consistent sharpness and reduces blurriness caused by fractional positioning,
+ /// particularly at small font sizes or low DPI settings.
+ ///
+ public BaselinePixelAlignment BaselinePixelAlignment { get; init; }
+
+ ///
+ /// Merges this instance with using inheritance semantics: unspecified values on this
+ /// instance are taken from .
+ ///
+ public TextOptions MergeWith(TextOptions other)
+ {
+ var textRenderingMode = TextRenderingMode;
+
+ if (textRenderingMode == TextRenderingMode.Unspecified)
+ {
+ textRenderingMode = other.TextRenderingMode;
+ }
+
+ var textHintingMode = TextHintingMode;
+
+ if (textHintingMode == TextHintingMode.Unspecified)
+ {
+ textHintingMode = other.TextHintingMode;
+ }
+
+ var baselinePixelAlignment = BaselinePixelAlignment;
+
+ if (baselinePixelAlignment == BaselinePixelAlignment.Unspecified)
+ {
+ baselinePixelAlignment = other.BaselinePixelAlignment;
+ }
+
+ return new TextOptions
+ {
+ TextRenderingMode = textRenderingMode,
+ TextHintingMode = textHintingMode,
+ BaselinePixelAlignment = baselinePixelAlignment
+ };
+ }
+
+ ///
+ /// Gets the TextOptions attached value for a visual.
+ ///
+ public static TextOptions GetTextOptions(Visual visual)
+ {
+ return visual.TextOptions;
+ }
+
+ ///
+ /// Sets the TextOptions attached value for a visual.
+ ///
+ public static void SetTextOptions(Visual visual, TextOptions value)
+ {
+ visual.TextOptions = value;
+ }
+
+ ///
+ /// Gets the TextRenderingMode attached property for a visual.
+ ///
+ public static TextRenderingMode GetTextRenderingMode(Visual visual)
+ {
+ return visual.TextOptions.TextRenderingMode;
+ }
+
+ ///
+ /// Sets the TextRenderingMode attached property for a visual.
+ ///
+ public static void SetTextRenderingMode(Visual visual, TextRenderingMode value)
+ {
+ visual.TextOptions = visual.TextOptions with { TextRenderingMode = value };
+ }
+
+ ///
+ /// Gets the TextHintingMode attached property for a visual.
+ ///
+ public static TextHintingMode GetTextHintingMode(Visual visual)
+ {
+ return visual.TextOptions.TextHintingMode;
+ }
+
+ ///
+ /// Sets the TextHintingMode attached property for a visual.
+ ///
+ public static void SetTextHintingMode(Visual visual, TextHintingMode value)
+ {
+ visual.TextOptions = visual.TextOptions with { TextHintingMode = value };
+ }
+
+ ///
+ /// Gets the BaselinePixelAlignment attached property for a visual.
+ ///
+ public static BaselinePixelAlignment GetBaselinePixelAlignment(Visual visual)
+ {
+ return visual.TextOptions.BaselinePixelAlignment;
+ }
+
+ ///
+ /// Sets the BaselinePixelAlignment attached property for a visual.
+ ///
+ public static void SetBaselinePixelAlignment(Visual visual, BaselinePixelAlignment value)
+ {
+ visual.TextOptions = visual.TextOptions with { BaselinePixelAlignment = value };
+ }
+ }
+}
diff --git a/src/Avalonia.Base/Media/TextRenderingMode.cs b/src/Avalonia.Base/Media/TextRenderingMode.cs
index 927d2bce73..dfc084720f 100644
--- a/src/Avalonia.Base/Media/TextRenderingMode.cs
+++ b/src/Avalonia.Base/Media/TextRenderingMode.cs
@@ -1,11 +1,36 @@
namespace Avalonia.Media
{
+ ///
+ /// Specifies how text glyphs are rendered in Avalonia.
+ /// Controls the smoothing and antialiasing applied during text rasterization.
+ ///
public enum TextRenderingMode : byte
{
+ ///
+ /// Rendering mode is not explicitly specified.
+ /// The system or platform default will be used.
+ ///
Unspecified,
- SubpixelAntialias,
+ ///
+ /// Glyphs are rendered with subpixel antialiasing.
+ /// This provides higher apparent resolution on LCD screens
+ /// by using the individual red, green, and blue subpixels.
+ ///
+ SubpixelAntialias,
+
+ ///
+ /// Glyphs are rendered with standard grayscale antialiasing.
+ /// This smooths edges without using subpixel information,
+ /// preserving shape fidelity across different display types.
+ ///
Antialias,
+
+ ///
+ /// Glyphs are rendered without antialiasing.
+ /// This produces sharp, aliased edges and may be useful
+ /// for pixel-art aesthetics or low-DPI environments.
+ ///
Alias
}
}
diff --git a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
index 1a813f7bbe..848620dae2 100644
--- a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
+++ b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
@@ -195,6 +195,17 @@ namespace Avalonia.Platform
///
void PopRenderOptions();
+ ///
+ /// Pushes text options for the drawing context.
+ ///
+ /// The text options.
+ void PushTextOptions(TextOptions textOptions);
+
+ ///
+ /// Pops the latest text options.
+ ///
+ void PopTextOptions();
+
///
/// Attempts to get an optional feature from the drawing context implementation.
///
diff --git a/src/Avalonia.Base/Platform/IGeometryContext.cs b/src/Avalonia.Base/Platform/IGeometryContext.cs
index 614b331761..4305dccd3f 100644
--- a/src/Avalonia.Base/Platform/IGeometryContext.cs
+++ b/src/Avalonia.Base/Platform/IGeometryContext.cs
@@ -18,7 +18,8 @@ namespace Avalonia.Platform
///
/// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction.
///
- void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection);
+ /// Whether the segment is stroked
+ void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked = true);
///
/// Begins a new figure.
@@ -33,20 +34,23 @@ namespace Avalonia.Platform
/// The first control point used to specify the shape of the curve.
/// The second control point used to specify the shape of the curve.
/// The destination point for the end of the curve.
- void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint);
+ /// Whether the segment is stroked
+ void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint, bool isStroked = true);
///
/// Draws a quadratic Bezier curve to the specified point
///
- /// Control point
- /// DestinationPoint
- void QuadraticBezierTo(Point controlPoint , Point endPoint);
+ /// The control point used to specify the shape of the curve.
+ /// The destination point for the end of the curve.
+ /// Whether the segment is stroked
+ void QuadraticBezierTo(Point controlPoint, Point endPoint, bool isStroked = true);
///
/// Draws a line to the specified point.
///
- /// The destination point.
- void LineTo(Point endPoint);
+ /// The destination point.
+ /// Whether the segment is stroked
+ void LineTo(Point point, bool isStroked = true);
///
/// Ends the figure started by .
diff --git a/src/Avalonia.Base/Platform/IGeometryContext2.cs b/src/Avalonia.Base/Platform/IGeometryContext2.cs
deleted file mode 100644
index 4142430e9d..0000000000
--- a/src/Avalonia.Base/Platform/IGeometryContext2.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using Avalonia.Media;
-
-namespace Avalonia.Platform
-{
- // TODO12 combine with IGeometryContext
- public interface IGeometryContext2 : IGeometryContext
- {
- ///
- /// Draws a line to the specified point.
- ///
- /// The destination point.
- /// Whether the segment is stroked
- void LineTo(Point point, bool isStroked);
-
- ///
- /// Draws an arc to the specified point.
- ///
- /// The destination point.
- /// The radii of an oval whose perimeter is used to draw the angle.
- /// The rotation angle (in radians) of the oval that specifies the curve.
- /// true to draw the arc greater than 180 degrees; otherwise, false.
- ///
- /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction.
- ///
- /// Whether the segment is stroked
- void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked);
-
- ///
- /// Draws a Bezier curve to the specified point.
- ///
- /// The first control point used to specify the shape of the curve.
- /// The second control point used to specify the shape of the curve.
- /// The destination point for the end of the curve.
- /// Whether the segment is stroked
- void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint, bool isStroked);
-
- ///
- /// Draws a quadratic Bezier curve to the specified point
- ///
- /// Control point
- /// DestinationPoint
- /// Whether the segment is stroked
- void QuadraticBezierTo(Point controlPoint, Point endPoint, bool isStroked);
- }
-
-}
diff --git a/src/Avalonia.Base/Platform/PathGeometryContext.cs b/src/Avalonia.Base/Platform/PathGeometryContext.cs
index bcb4f2a272..a20c7cf26b 100644
--- a/src/Avalonia.Base/Platform/PathGeometryContext.cs
+++ b/src/Avalonia.Base/Platform/PathGeometryContext.cs
@@ -21,7 +21,7 @@ namespace Avalonia.Visuals.Platform
}
///
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
+ public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked = true)
{
var arcSegment = new ArcSegment
{
@@ -29,7 +29,8 @@ namespace Avalonia.Visuals.Platform
RotationAngle = rotationAngle,
IsLargeArc = isLargeArc,
SweepDirection = sweepDirection,
- Point = point
+ Point = point,
+ IsStroked = isStroked
};
CurrentFigureSegments().Add(arcSegment);
@@ -47,27 +48,39 @@ namespace Avalonia.Visuals.Platform
}
///
- public void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint)
+ public void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint, bool isStroked = true)
{
- var bezierSegment = new BezierSegment { Point1 = controlPoint1, Point2 = controlPoint2, Point3 = endPoint };
+ var bezierSegment = new BezierSegment
+ {
+ Point1 = controlPoint1,
+ Point2 = controlPoint2,
+ Point3 = endPoint,
+ IsStroked = isStroked
+ };
CurrentFigureSegments().Add(bezierSegment);
}
///
- public void QuadraticBezierTo(Point controlPoint , Point endPoint)
+ public void QuadraticBezierTo(Point controlPoint , Point endPoint, bool isStroked = true)
{
- var quadraticBezierSegment = new QuadraticBezierSegment { Point1 = controlPoint , Point2 = endPoint };
+ var quadraticBezierSegment = new QuadraticBezierSegment
+ {
+ Point1 = controlPoint,
+ Point2 = endPoint,
+ IsStroked = isStroked
+ };
CurrentFigureSegments().Add(quadraticBezierSegment);
}
///
- public void LineTo(Point endPoint)
+ public void LineTo(Point point, bool isStroked = true)
{
var lineSegment = new LineSegment
{
- Point = endPoint
+ Point = point,
+ IsStroked = isStroked
};
CurrentFigureSegments().Add(lineSegment);
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs
index ac0a5c4cb7..c7d10f69a1 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs
@@ -232,3 +232,18 @@ class RenderDataRenderOptionsNode : RenderDataPushNode
context.Context.PopRenderOptions();
}
}
+
+class RenderDataTextOptionsNode : RenderDataPushNode
+{
+ public TextOptions TextOptions { get; set; }
+
+ public override void Push(ref RenderDataNodeRenderContext context)
+ {
+ context.Context.PushTextOptions(TextOptions);
+ }
+
+ public override void Pop(ref RenderDataNodeRenderContext context)
+ {
+ context.Context.PopTextOptions();
+ }
+}
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs
index 870a084d31..ead6a3f730 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs
@@ -264,6 +264,10 @@ internal class RenderDataDrawingContext : DrawingContext
RenderOptions = renderOptions
});
+ protected override void PushTextOptionsCore(TextOptions textOptions) => Push(new RenderDataTextOptionsNode()
+ {
+ TextOptions = textOptions
+ });
protected override void PopClipCore() => Pop();
@@ -277,6 +281,8 @@ internal class RenderDataDrawingContext : DrawingContext
protected override void PopRenderOptionsCore() => Pop();
+ protected override void PopTextOptionsCore() => Pop();
+
internal override void DrawBitmap(IRef? source, double opacity, Rect sourceRect, Rect destRect)
{
if (source == null || sourceRect.IsEmpty() || destRect.IsEmpty())
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs
index ee0447629a..d26aec0d69 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs
@@ -22,6 +22,7 @@ internal partial class CompositorDrawingContextProxy
PushOpacityMask,
PushGeometryClip,
PushRenderOptions,
+ PushTextOptions,
PushEffect
}
@@ -43,6 +44,7 @@ internal partial class CompositorDrawingContextProxy
[FieldOffset(0)] public Matrix Transform;
[FieldOffset(0)] public RenderOptions RenderOptions;
+ [FieldOffset(0)] public TextOptions TextOptions;
// PushClip/PushOpacityMask
[FieldOffset(0)] public bool IsRoundRect;
@@ -148,6 +150,8 @@ internal partial class CompositorDrawingContextProxy
}
else if (cmd.Type == PendingCommandType.PushRenderOptions)
_impl.PushRenderOptions(cmd.DataUnion.RenderOptions);
+ else if (cmd.Type == PendingCommandType.PushTextOptions)
+ _impl.PushTextOptions(cmd.DataUnion.TextOptions);
else
Debug.Assert(false);
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
index 6b4982c490..81041a659d 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
@@ -260,6 +260,18 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
});
}
+ public void PushTextOptions(TextOptions textOptions)
+ {
+ AddCommand(new()
+ {
+ Type = PendingCommandType.PushTextOptions,
+ DataUnion =
+ {
+ TextOptions = textOptions
+ }
+ });
+ }
+
public void PopRenderOptions()
{
if (!TryDiscardOrFlush(PendingCommandType.PushRenderOptions))
@@ -269,6 +281,15 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
}
}
+ public void PopTextOptions()
+ {
+ if (!TryDiscardOrFlush(PendingCommandType.PushTextOptions))
+ {
+ _impl.PopTextOptions();
+ RestoreTransform();
+ }
+ }
+
public object? GetFeature(Type t)
{
Flush();
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
index c2d43f5667..9225dd6ac6 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
@@ -62,6 +62,12 @@ namespace Avalonia.Rendering.Composition.Server
if (applyRenderOptions)
canvas.PushRenderOptions(RenderOptions);
+
+ var applyTextOptions = TextOptions != default;
+
+ if (applyTextOptions)
+ canvas.PushTextOptions(TextOptions);
+
var needPopEffect = PushEffect(canvas);
if (Opacity != 1)
@@ -88,7 +94,9 @@ namespace Avalonia.Rendering.Composition.Server
if (needPopEffect)
canvas.PopEffect();
- if(applyRenderOptions)
+ if (applyTextOptions)
+ canvas.PopTextOptions();
+ if (applyRenderOptions)
canvas.PopRenderOptions();
}
diff --git a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs
index d308f532da..f054e77db8 100644
--- a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs
+++ b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs
@@ -50,6 +50,7 @@ internal class ImmediateRenderer
transform = Matrix.CreateTranslation(bounds.Position);
}
+ using (visual.TextOptions != default ? context.PushTextOptions(visual.TextOptions) : default(DrawingContext.PushedState?))
using (visual.RenderOptions != default ? context.PushRenderOptions(visual.RenderOptions) : default(DrawingContext.PushedState?))
using (context.PushTransform(transform))
using (visual.HasMirrorTransform ? context.PushTransform(new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0)) : default(DrawingContext.PushedState?))
diff --git a/src/Avalonia.Base/Utilities/StringTokenizer.cs b/src/Avalonia.Base/Utilities/StringTokenizer.cs
deleted file mode 100644
index e83ef8c479..0000000000
--- a/src/Avalonia.Base/Utilities/StringTokenizer.cs
+++ /dev/null
@@ -1,245 +0,0 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using static System.Char;
-
-namespace Avalonia.Utilities
-{
- // TODO12: Remove this struct in 12.0 (breaking change)
-
- [Obsolete("This type has been superseded by SpanStringTokenizer.")]
-#if !BUILDTASK
- public
-#endif
- record struct StringTokenizer : IDisposable
- {
- private const char DefaultSeparatorChar = ',';
-
- private readonly string _s;
- private readonly int _length;
- private readonly char _separator;
- private readonly string? _exceptionMessage;
- private readonly IFormatProvider _formatProvider;
- private int _index;
- private int _tokenIndex;
- private int _tokenLength;
-
- public StringTokenizer(string s, IFormatProvider formatProvider, string? exceptionMessage = null)
- : this(s, GetSeparatorFromFormatProvider(formatProvider), exceptionMessage)
- {
- _formatProvider = formatProvider;
- }
-
- public StringTokenizer(string s, char separator = DefaultSeparatorChar, string? exceptionMessage = null)
- {
- _s = s ?? throw new ArgumentNullException(nameof(s));
- _length = s?.Length ?? 0;
- _separator = separator;
- _exceptionMessage = exceptionMessage;
- _formatProvider = CultureInfo.InvariantCulture;
- _index = 0;
- _tokenIndex = -1;
- _tokenLength = 0;
-
- while (_index < _length && IsWhiteSpace(_s, _index))
- {
- _index++;
- }
- }
-
- public string? CurrentToken => _tokenIndex < 0 ? null : _s.Substring(_tokenIndex, _tokenLength);
-
- public ReadOnlySpan CurrentTokenSpan => _tokenIndex < 0 ? ReadOnlySpan.Empty : _s.AsSpan().Slice(_tokenIndex, _tokenLength);
-
- public void Dispose()
- {
- if (_index != _length)
- {
- throw GetFormatException();
- }
- }
-
- public bool TryReadInt32(out Int32 result, char? separator = null)
- {
- if (TryReadSpan(out var stringResult, separator) &&
- SpanHelpers.TryParseInt(stringResult, NumberStyles.Integer, _formatProvider, out result))
- {
- return true;
- }
- else
- {
- result = default;
- return false;
- }
- }
-
- public int ReadInt32(char? separator = null)
- {
- if (!TryReadInt32(out var result, separator))
- {
- throw GetFormatException();
- }
-
- return result;
- }
-
- public bool TryReadDouble(out double result, char? separator = null)
- {
- if (TryReadSpan(out var stringResult, separator) &&
- SpanHelpers.TryParseDouble(stringResult, NumberStyles.Float, _formatProvider, out result))
- {
- return true;
- }
- else
- {
- result = default;
- return false;
- }
- }
-
- public double ReadDouble(char? separator = null)
- {
- if (!TryReadDouble(out var result, separator))
- {
- throw GetFormatException();
- }
-
- return result;
- }
-
- public bool TryReadString([NotNull] out string result, char? separator = null)
- {
- var success = TryReadToken(separator ?? _separator);
- result = CurrentTokenSpan.ToString();
- return success;
- }
-
- public string ReadString(char? separator = null)
- {
- if (!TryReadString(out var result, separator))
- {
- throw GetFormatException();
- }
-
- return result;
- }
-
- public bool TryReadSpan(out ReadOnlySpan result, char? separator = null)
- {
- var success = TryReadToken(separator ?? _separator);
- result = CurrentTokenSpan;
- return success;
- }
-
- public ReadOnlySpan ReadSpan(char? separator = null)
- {
- if (!TryReadSpan(out var result, separator))
- {
- throw GetFormatException();
- }
-
- return result;
- }
-
- private bool TryReadToken(char separator)
- {
- _tokenIndex = -1;
-
- if (_index >= _length)
- {
- return false;
- }
-
- var c = _s[_index];
-
- var index = _index;
- var length = 0;
-
- while (_index < _length)
- {
- c = _s[_index];
-
- if (IsWhiteSpace(c) || c == separator)
- {
- break;
- }
-
- _index++;
- length++;
- }
-
- SkipToNextToken(separator);
-
- _tokenIndex = index;
- _tokenLength = length;
-
- if (_tokenLength < 1)
- {
- throw GetFormatException();
- }
-
- return true;
- }
-
- private void SkipToNextToken(char separator)
- {
- if (_index < _length)
- {
- var c = _s[_index];
-
- if (c != separator && !IsWhiteSpace(c))
- {
- throw GetFormatException();
- }
-
- var length = 0;
-
- while (_index < _length)
- {
- c = _s[_index];
-
- if (c == separator)
- {
- length++;
- _index++;
-
- if (length > 1)
- {
- throw GetFormatException();
- }
- }
- else
- {
- if (!IsWhiteSpace(c))
- {
- break;
- }
-
- _index++;
- }
- }
-
- if (length > 0 && _index >= _length)
- {
- throw GetFormatException();
- }
- }
- }
-
- private FormatException GetFormatException() =>
- _exceptionMessage != null ? new FormatException(_exceptionMessage) : new FormatException();
-
- private static char GetSeparatorFromFormatProvider(IFormatProvider provider)
- {
- var c = DefaultSeparatorChar;
-
- var formatInfo = NumberFormatInfo.GetInstance(provider);
- if (formatInfo.NumberDecimalSeparator.Length > 0 && c == formatInfo.NumberDecimalSeparator[0])
- {
- c = ';';
- }
-
- return c;
- }
- }
-}
diff --git a/src/Avalonia.Base/Visual.Composition.cs b/src/Avalonia.Base/Visual.Composition.cs
index f521f2a3f2..a1f90a5407 100644
--- a/src/Avalonia.Base/Visual.Composition.cs
+++ b/src/Avalonia.Base/Visual.Composition.cs
@@ -148,6 +148,7 @@ public partial class Visual
comp.Effect = Effect?.ToImmutable();
comp.RenderOptions = RenderOptions;
+ comp.TextOptions = TextOptions;
var renderTransform = Matrix.Identity;
@@ -163,4 +164,4 @@ public partial class Visual
comp.TransformMatrix = renderTransform;
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs
index 6b10fa228c..ee960cee1e 100644
--- a/src/Avalonia.Base/Visual.cs
+++ b/src/Avalonia.Base/Visual.cs
@@ -1,5 +1,3 @@
-
-
#nullable enable
using System;
@@ -39,7 +37,7 @@ namespace Avalonia
///
public static readonly DirectProperty BoundsProperty =
AvaloniaProperty.RegisterDirect(nameof(Bounds), o => o.Bounds);
-
+
///
/// Defines the property.
///
@@ -51,7 +49,7 @@ namespace Avalonia
///
public static readonly StyledProperty ClipProperty =
AvaloniaProperty.Register(nameof(Clip));
-
+
///
/// Defines the property.
///
@@ -69,7 +67,7 @@ namespace Avalonia
///
public static readonly StyledProperty OpacityMaskProperty =
AvaloniaProperty.Register(nameof(OpacityMask));
-
+
///
/// Defines the property.
///
@@ -113,7 +111,7 @@ namespace Avalonia
///
public static readonly StyledProperty ZIndexProperty =
AvaloniaProperty.Register(nameof(ZIndex));
-
+
private static readonly WeakEvent InvalidatedWeakEvent =
WeakEvent.Register(
(s, h) => s.Invalidated += h,
@@ -124,6 +122,8 @@ namespace Avalonia
private Visual? _visualParent;
private bool _hasMirrorTransform;
private TargetWeakEventSubscriber? _affectsRenderWeakSubscriber;
+ private RenderOptions _renderOptions;
+ private TextOptions _textOptions;
///
/// Initializes static members of the class.
@@ -201,7 +201,7 @@ namespace Avalonia
/// Gets a value indicating whether this control and all its parents are visible.
///
public bool IsEffectivelyVisible { get; private set; } = true;
-
+
///
/// Updates the property based on the parent's
/// .
@@ -218,7 +218,7 @@ namespace Avalonia
// PERF-SENSITIVE: This is called on entire hierarchy and using foreach or LINQ
// will cause extra allocations and overhead.
-
+
var children = VisualChildren;
// ReSharper disable once ForCanBeConvertedToForeach
@@ -255,7 +255,7 @@ namespace Avalonia
get { return GetValue(OpacityMaskProperty); }
set { SetValue(OpacityMaskProperty, value); }
}
-
+
///
/// Gets or sets the effect of the control.
///
@@ -269,8 +269,8 @@ namespace Avalonia
///
/// Gets or sets a value indicating whether to apply mirror transform on this control.
///
- public bool HasMirrorTransform
- {
+ public bool HasMirrorTransform
+ {
get { return _hasMirrorTransform; }
protected set { SetAndRaise(HasMirrorTransformProperty, ref _hasMirrorTransform, value); }
}
@@ -326,7 +326,25 @@ namespace Avalonia
///
protected internal IRenderRoot? VisualRoot => _visualRoot;
- internal RenderOptions RenderOptions { get; set; }
+ internal RenderOptions RenderOptions
+ {
+ get => _renderOptions;
+ set
+ {
+ _renderOptions = value;
+ InvalidateVisual();
+ }
+ }
+
+ internal TextOptions TextOptions
+ {
+ get => _textOptions;
+ set
+ {
+ _textOptions = value;
+ InvalidateVisual();
+ }
+ }
internal bool HasNonUniformZIndexChildren { get; private set; }
@@ -413,8 +431,8 @@ namespace Avalonia
sender.InvalidateVisual();
}
});
-
-
+
+
var invalidateAndSubscribeObserver = new AnonymousObserver(
static e =>
{
@@ -466,7 +484,7 @@ namespace Avalonia
if (change.Property == IsVisibleProperty)
{
UpdateIsEffectivelyVisible(VisualParent?.IsEffectivelyVisible ?? true);
- }
+ }
else if (change.Property == FlowDirectionProperty)
{
InvalidateMirrorTransform();
@@ -477,7 +495,7 @@ namespace Avalonia
}
}
}
-
+
protected override void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.LogicalChildrenCollectionChanged(sender, e);
@@ -515,12 +533,12 @@ namespace Avalonia
OnAttachedToVisualTree(e);
AttachedToVisualTree?.Invoke(this, e);
InvalidateVisual();
-
+
_visualRoot.Renderer.RecalculateChildren(_visualParent);
-
+
if (ZIndex != 0)
_visualParent.HasNonUniformZIndexChildren = true;
-
+
var visualChildren = VisualChildren;
var visualChildrenCount = visualChildren.Count;
@@ -617,7 +635,7 @@ namespace Avalonia
{
newTransform.Changed += sender.RenderTransformChanged;
}
-
+
sender.InvalidateVisual();
}
}
@@ -651,7 +669,7 @@ namespace Avalonia
var parent = sender?.VisualParent;
if (sender?.ZIndex != 0 && parent is Visual parentVisual)
parentVisual.HasNonUniformZIndexChildren = true;
-
+
sender?.InvalidateVisual();
parent?.VisualRoot?.Renderer.RecalculateChildren(parent);
}
@@ -721,7 +739,7 @@ namespace Avalonia
break;
}
}
-
+
private static void SetVisualParent(IList children, Visual? parent)
{
var count = children.Count;
@@ -729,7 +747,7 @@ namespace Avalonia
for (var i = 0; i < count; i++)
{
var visual = (Visual) children[i]!;
-
+
visual.SetVisualParent(parent);
}
}
diff --git a/src/Avalonia.Base/composition-schema.xml b/src/Avalonia.Base/composition-schema.xml
index ce989296b1..dd1d284cd5 100644
--- a/src/Avalonia.Base/composition-schema.xml
+++ b/src/Avalonia.Base/composition-schema.xml
@@ -34,6 +34,7 @@
+
diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
index 65929f1357..bc6380a012 100644
--- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
+++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
@@ -6,6 +6,7 @@
tools
$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL
true
+ true
$(NoWarn);NU1605;CS8632
embedded
false
@@ -61,9 +62,6 @@
Markup/%(RecursiveDir)%(FileName)%(Extension)
-
- Markup/%(RecursiveDir)%(FileName)%(Extension)
-
Markup/%(RecursiveDir)%(FileName)%(Extension)
diff --git a/src/Avalonia.Controls/Automation/AutomationProperties.cs b/src/Avalonia.Controls/Automation/AutomationProperties.cs
index 4e11715c56..e46dcb0eb2 100644
--- a/src/Avalonia.Controls/Automation/AutomationProperties.cs
+++ b/src/Avalonia.Controls/Automation/AutomationProperties.cs
@@ -211,7 +211,7 @@ namespace Avalonia.Automation
/// Defines the AutomationProperties.LiveSetting attached property.
///
///
- /// This property currently has no effect.
+ /// This property affects the default value for and controls whether live region changed events are emitted.
///
public static readonly AttachedProperty LiveSettingProperty =
AvaloniaProperty.RegisterAttached(
diff --git a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs
index 65f9503061..56111bdc83 100644
--- a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs
@@ -47,6 +47,7 @@ namespace Avalonia.Automation.Peers
Table,
TitleBar,
Separator,
+ Expander,
}
public enum AutomationLandmarkType
@@ -475,6 +476,12 @@ namespace Avalonia.Automation.Peers
/// true if a context menu is present for the element; otherwise false.
public bool ShowContextMenu() => ShowContextMenuCore();
+ ///
+ /// Gets the current live setting that is associated with this this automation peer.
+ ///
+ /// The live setting to use for automation.
+ public AutomationLiveSetting GetLiveSetting() => GetLiveSettingCore();
+
///
/// Tries to get a provider of the specified type from the peer.
///
@@ -536,6 +543,7 @@ namespace Avalonia.Automation.Peers
AutomationControlType.SplitButton => "split button",
AutomationControlType.HeaderItem => "header item",
AutomationControlType.TitleBar => "title bar",
+ AutomationControlType.Expander => "group",
AutomationControlType.None => (GetLandmarkType()?.ToString() ?? controlType.ToString()).ToLowerInvariant(),
_ => controlType.ToString().ToLowerInvariant(),
};
@@ -563,6 +571,7 @@ namespace Avalonia.Automation.Peers
protected virtual bool IsOffscreenCore() => false;
protected abstract void SetFocusCore();
protected abstract bool ShowContextMenuCore();
+ protected virtual AutomationLiveSetting GetLiveSettingCore() => AutomationLiveSetting.Off;
protected virtual AutomationControlType GetControlTypeOverrideCore()
{
diff --git a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
index ef14be0169..c59ba6b148 100644
--- a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
@@ -185,6 +185,8 @@ namespace Avalonia.Automation.Peers
return false;
}
+ protected override AutomationLiveSetting GetLiveSettingCore() => AutomationProperties.GetLiveSetting(Owner);
+
protected internal override bool TrySetParent(AutomationPeer? parent)
{
_parent = parent;
diff --git a/src/Avalonia.Controls/Automation/Peers/ExpanderAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ExpanderAutomationPeer.cs
new file mode 100644
index 0000000000..a23e8f045a
--- /dev/null
+++ b/src/Avalonia.Controls/Automation/Peers/ExpanderAutomationPeer.cs
@@ -0,0 +1,47 @@
+using Avalonia.Automation;
+using Avalonia.Automation.Peers;
+using Avalonia.Automation.Provider;
+
+namespace Avalonia.Controls.Automation.Peers
+{
+ public class ExpanderAutomationPeer : ControlAutomationPeer,
+ IExpandCollapseProvider
+ {
+ public ExpanderAutomationPeer(Control owner)
+ : base(owner)
+ {
+ owner.PropertyChanged += OwnerPropertyChanged;
+ }
+
+ public new Expander Owner => (Expander)base.Owner;
+
+ public ExpandCollapseState ExpandCollapseState => ToState(Owner.IsExpanded);
+ public bool ShowsMenu => false;
+ public void Collapse() => Owner.IsExpanded = false;
+ public void Expand() => Owner.IsExpanded = true;
+
+ protected override AutomationControlType GetAutomationControlTypeCore()
+ {
+ return AutomationControlType.Expander;
+ }
+
+ private void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
+ {
+ if (e.Property == Expander.IsExpandedProperty)
+ {
+ RaisePropertyChangedEvent(
+ ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty,
+ ToState((bool)e.OldValue!),
+ ToState((bool)e.NewValue!));
+ }
+ }
+
+ private static ExpandCollapseState ToState(bool value)
+ {
+ return value ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed;
+ }
+
+ protected override bool IsContentElementCore() => true;
+ protected override bool IsControlElementCore() => true;
+ }
+}
diff --git a/src/Avalonia.Controls/Automation/Peers/TextBlockAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/TextBlockAutomationPeer.cs
index bc550b6937..e1218384d3 100644
--- a/src/Avalonia.Controls/Automation/Peers/TextBlockAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/TextBlockAutomationPeer.cs
@@ -7,6 +7,16 @@ namespace Avalonia.Automation.Peers
public TextBlockAutomationPeer(TextBlock owner)
: base(owner)
{
+ Owner.PropertyChanged += (a, e) =>
+ {
+ if (e.Property == TextBlock.TextProperty)
+ {
+ RaisePropertyChangedEvent(
+ AutomationElementIdentifiers.NameProperty,
+ e.OldValue,
+ e.NewValue);
+ }
+ };
}
public new TextBlock Owner => (TextBlock)base.Owner;
diff --git a/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs
index e6920c1e02..4bd606dd6e 100644
--- a/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/TitleBarAutomationPeer.cs
@@ -10,7 +10,7 @@ internal class TitleBarAutomationPeer : ControlAutomationPeer
{
}
- protected override bool IsContentElementCore() => true;
+ protected override bool IsContentElementCore() => false;
protected override string GetClassNameCore()
{
diff --git a/src/Avalonia.Controls/Automation/Peers/ToggleButtonAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ToggleButtonAutomationPeer.cs
index 979d54f48e..99b3cdd657 100644
--- a/src/Avalonia.Controls/Automation/Peers/ToggleButtonAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/ToggleButtonAutomationPeer.cs
@@ -1,4 +1,5 @@
using Avalonia.Automation.Provider;
+using Avalonia.Controls.Automation;
using Avalonia.Controls.Primitives;
namespace Avalonia.Automation.Peers
@@ -8,19 +9,28 @@ namespace Avalonia.Automation.Peers
public ToggleButtonAutomationPeer(ToggleButton owner)
: base(owner)
{
+ Owner.PropertyChanged += (a, e) =>
+ {
+ if (e.Property == ToggleButton.IsCheckedProperty)
+ {
+ RaisePropertyChangedEvent(
+ TogglePatternIdentifiers.ToggleStateProperty,
+ ToState((bool?)e.OldValue),
+ ToState((bool?)e.NewValue));
+ }
+ };
}
public new ToggleButton Owner => (ToggleButton)base.Owner;
- ToggleState IToggleProvider.ToggleState
+ private ToggleState ToState(bool? value) => value switch
{
- get => Owner.IsChecked switch
- {
- true => ToggleState.On,
- false => ToggleState.Off,
- null => ToggleState.Indeterminate,
- };
- }
+ true => ToggleState.On,
+ false => ToggleState.Off,
+ null => ToggleState.Indeterminate,
+ };
+
+ ToggleState IToggleProvider.ToggleState => ToState(Owner.IsChecked);
void IToggleProvider.Toggle()
{
diff --git a/src/Avalonia.Controls/Automation/TogglePatternIdentifiers.cs b/src/Avalonia.Controls/Automation/TogglePatternIdentifiers.cs
new file mode 100644
index 0000000000..be6b1c8fb2
--- /dev/null
+++ b/src/Avalonia.Controls/Automation/TogglePatternIdentifiers.cs
@@ -0,0 +1,15 @@
+using Avalonia.Automation.Provider;
+
+namespace Avalonia.Automation
+{
+ ///
+ /// Contains values used as identifiers by .
+ ///
+ public static class TogglePatternIdentifiers
+ {
+ ///
+ /// Identifies the property.
+ ///
+ public static AutomationProperty ToggleStateProperty { get; } = new AutomationProperty();
+ }
+}
diff --git a/src/Avalonia.Controls/Design.cs b/src/Avalonia.Controls/Design.cs
index 9d6bb93ebb..1e7912d75f 100644
--- a/src/Avalonia.Controls/Design.cs
+++ b/src/Avalonia.Controls/Design.cs
@@ -127,22 +127,6 @@ namespace Avalonia.Controls
///
public static readonly AttachedProperty PreviewWithProperty = AvaloniaProperty
.RegisterAttached("PreviewWith", typeof (Design));
-
- ///
- /// Sets a preview template for the specified at design-time.
- ///
- ///
- /// This method allows you to specify a substitute control to be rendered in the previewer
- /// for a given object.
- ///
- /// The target object.
- /// The preview control.
- // TODO12: Remove this overload in Avalonia 12
- [Obsolete("Use SetPreviewWith(AvaloniaObject, ITemplate) overload instead. Use from XAML")]
- public static void SetPreviewWith(AvaloniaObject target, Control? control)
- {
- s_previewWith[target] = control is not null ? new FuncTemplate(() => control) : null;
- }
///
/// Sets a preview template for the specified at design-time.
diff --git a/src/Avalonia.Controls/Documents/Inline.cs b/src/Avalonia.Controls/Documents/Inline.cs
index 1ededcf81c..fe526e9204 100644
--- a/src/Avalonia.Controls/Documents/Inline.cs
+++ b/src/Avalonia.Controls/Documents/Inline.cs
@@ -10,11 +10,10 @@ namespace Avalonia.Controls.Documents
///
public abstract class Inline : TextElement
{
- // TODO12: change the field type to an AttachedProperty for consistency (breaking change)
///
/// AvaloniaProperty for property.
///
- public static readonly StyledProperty TextDecorationsProperty =
+ public static readonly AttachedProperty TextDecorationsProperty =
AvaloniaProperty.RegisterAttached(
nameof(TextDecorations),
inherits: true);
diff --git a/src/Avalonia.Controls/Expander.cs b/src/Avalonia.Controls/Expander.cs
index aeee9f07ea..eb10516a82 100644
--- a/src/Avalonia.Controls/Expander.cs
+++ b/src/Avalonia.Controls/Expander.cs
@@ -1,6 +1,8 @@
using System;
using System.Threading;
using Avalonia.Animation;
+using Avalonia.Automation.Peers;
+using Avalonia.Controls.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
@@ -274,6 +276,11 @@ namespace Avalonia.Controls
}
}
+ protected override AutomationPeer OnCreateAutomationPeer()
+ {
+ return new ExpanderAutomationPeer(this);
+ }
+
///
/// Updates the visual state of the control by applying latest PseudoClasses.
///
diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs
index 4622fee005..c3b62860c7 100644
--- a/src/Avalonia.Controls/Platform/Screen.cs
+++ b/src/Avalonia.Controls/Platform/Screen.cs
@@ -1,8 +1,5 @@
using System;
using System.ComponentModel;
-using System.Runtime.CompilerServices;
-using Avalonia.Diagnostics;
-using Avalonia.Metadata;
using Avalonia.Utilities;
namespace Avalonia.Platform
@@ -45,7 +42,7 @@ namespace Avalonia.Platform
///
/// Represents a single display screen.
///
- public class Screen : IEquatable
+ public abstract class Screen : IEquatable
{
///
/// Gets the device name associated with a display.
@@ -96,22 +93,6 @@ namespace Avalonia.Platform
[Obsolete("Use the IsPrimary property instead.", true), EditorBrowsable(EditorBrowsableState.Never)]
public bool Primary => IsPrimary;
- ///
- /// Initializes a new instance of the class.
- ///
- /// The scaling factor applied to the screen by the operating system.
- /// The overall pixel-size of the screen.
- /// The actual working-area pixel-size of the screen.
- /// Whether the screen is the primary one.
- [Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)]
- public Screen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary)
- {
- Scaling = scaling;
- Bounds = bounds;
- WorkingArea = workingArea;
- IsPrimary = isPrimary;
- }
-
private protected Screen() { }
///
@@ -123,19 +104,15 @@ namespace Avalonia.Platform
///
public virtual IPlatformHandle? TryGetPlatformHandle() => null;
- // TODO12: make abstract
///
- public override int GetHashCode()
- => RuntimeHelpers.GetHashCode(this);
+ public abstract override int GetHashCode();
///
public override bool Equals(object? obj)
=> obj is Screen other && Equals(other);
- // TODO12: make abstract
///
- public virtual bool Equals(Screen? other)
- => ReferenceEquals(this, other);
+ public abstract bool Equals(Screen? other);
public static bool operator ==(Screen? left, Screen? right)
{
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
index 3b9f0b08d3..2d775e2be0 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
@@ -45,35 +45,35 @@ namespace Avalonia.Controls.Presenters
/// Gets the owner .
///
internal ItemsControl? ItemsControl { get; private set; }
+
+ private bool CanHorizontallyScroll
+ => _logicalScrollable?.CanHorizontallyScroll ?? false;
- bool ILogicalScrollable.CanHorizontallyScroll
+ bool ILogicalScrollable.CanHorizontallyScroll
{
- get => _logicalScrollable?.CanHorizontallyScroll ?? false;
- set
- {
- if (_logicalScrollable is not null)
- _logicalScrollable.CanHorizontallyScroll = value;
- }
+ get => CanHorizontallyScroll;
+ set => _logicalScrollable?.CanHorizontallyScroll = value;
}
- bool ILogicalScrollable.CanVerticallyScroll
+ bool IScrollable.CanHorizontallyScroll
+ => CanHorizontallyScroll;
+
+ private bool CanVerticallyScroll
+ => _logicalScrollable?.CanVerticallyScroll ?? false;
+
+ bool ILogicalScrollable.CanVerticallyScroll
{
- get => _logicalScrollable?.CanVerticallyScroll ?? false;
- set
- {
- if (_logicalScrollable is not null)
- _logicalScrollable.CanVerticallyScroll = value;
- }
+ get => CanVerticallyScroll;
+ set => _logicalScrollable?.CanVerticallyScroll = value;
}
+ bool IScrollable.CanVerticallyScroll
+ => CanVerticallyScroll;
+
Vector IScrollable.Offset
{
get => _logicalScrollable?.Offset ?? default;
- set
- {
- if (_logicalScrollable is not null)
- _logicalScrollable.Offset = value;
- }
+ set => _logicalScrollable?.Offset = value;
}
bool ILogicalScrollable.IsLogicalScrollEnabled => _logicalScrollable?.IsLogicalScrollEnabled ?? false;
diff --git a/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs b/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs
index e0c6241620..6c96287c10 100644
--- a/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs
+++ b/src/Avalonia.Controls/Primitives/ILogicalScrollable.cs
@@ -19,12 +19,12 @@ namespace Avalonia.Controls.Primitives
///
/// Gets or sets a value indicating whether the content can be scrolled horizontally.
///
- bool CanHorizontallyScroll { get; set; }
+ new bool CanHorizontallyScroll { get; set; }
///
/// Gets or sets a value indicating whether the content can be scrolled horizontally.
///
- bool CanVerticallyScroll { get; set; }
+ new bool CanVerticallyScroll { get; set; }
///
/// Gets a value indicating whether logical scrolling is enabled on the control.
diff --git a/src/Avalonia.Controls/Primitives/TextSearch.cs b/src/Avalonia.Controls/Primitives/TextSearch.cs
index 5099567630..aa83266683 100644
--- a/src/Avalonia.Controls/Primitives/TextSearch.cs
+++ b/src/Avalonia.Controls/Primitives/TextSearch.cs
@@ -24,22 +24,20 @@ namespace Avalonia.Controls.Primitives
public static readonly AttachedProperty TextBindingProperty
= AvaloniaProperty.RegisterAttached("TextBinding", typeof(TextSearch));
- // TODO12: Control should be Interactive to match the property definition.
///
/// Sets the value of the attached property to a given .
///
/// The control.
/// The search text to set.
- public static void SetText(Control control, string? text)
+ public static void SetText(Interactive control, string? text)
=> control.SetValue(TextProperty, text);
- // TODO12: Control should be Interactive to match the property definition.
///
/// Gets the value of the attached property from a given .
///
/// The control.
/// The search text.
- public static string? GetText(Control control)
+ public static string? GetText(Interactive control)
=> control.GetValue(TextProperty);
///
diff --git a/src/Avalonia.Controls/ScrollViewer.cs b/src/Avalonia.Controls/ScrollViewer.cs
index 3152eec2db..e93180fff4 100644
--- a/src/Avalonia.Controls/ScrollViewer.cs
+++ b/src/Avalonia.Controls/ScrollViewer.cs
@@ -14,7 +14,7 @@ namespace Avalonia.Controls
///
[TemplatePart("PART_HorizontalScrollBar", typeof(ScrollBar))]
[TemplatePart("PART_VerticalScrollBar", typeof(ScrollBar))]
- public class ScrollViewer : ContentControl, IScrollable, IScrollAnchorProvider, IInternalScroller
+ public class ScrollViewer : ContentControl, IScrollable, IScrollAnchorProvider
{
///
/// Defines the property.
@@ -284,7 +284,7 @@ namespace Avalonia.Controls
get => HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled;
}
- bool IInternalScroller.CanHorizontallyScroll => CanHorizontallyScroll;
+ bool IScrollable.CanHorizontallyScroll => CanHorizontallyScroll;
///
/// Gets a value indicating whether the viewer can scroll vertically.
@@ -294,7 +294,7 @@ namespace Avalonia.Controls
get => VerticalScrollBarVisibility != ScrollBarVisibility.Disabled;
}
- bool IInternalScroller.CanVerticallyScroll => CanVerticallyScroll;
+ bool IScrollable.CanVerticallyScroll => CanVerticallyScroll;
///
public Control? CurrentAnchor => (Presenter as IScrollAnchorProvider)?.CurrentAnchor;
diff --git a/src/Avalonia.Controls/VirtualizingCarouselPanel.cs b/src/Avalonia.Controls/VirtualizingCarouselPanel.cs
index 8b67f01fb1..454069b4b2 100644
--- a/src/Avalonia.Controls/VirtualizingCarouselPanel.cs
+++ b/src/Avalonia.Controls/VirtualizingCarouselPanel.cs
@@ -29,9 +29,23 @@ namespace Avalonia.Controls
private int _transitionFromIndex = -1;
private CancellationTokenSource? _transition;
private EventHandler? _scrollInvalidated;
+ private bool _canHorizontallyScroll;
+ private bool _canVerticallyScroll;
- bool ILogicalScrollable.CanHorizontallyScroll { get; set; }
- bool ILogicalScrollable.CanVerticallyScroll { get; set; }
+ bool ILogicalScrollable.CanHorizontallyScroll
+ {
+ get => _canHorizontallyScroll;
+ set => _canHorizontallyScroll = value;
+ }
+
+ bool ILogicalScrollable.CanVerticallyScroll
+ {
+ get => _canVerticallyScroll;
+ set => _canVerticallyScroll = value;
+ }
+
+ bool IScrollable.CanHorizontallyScroll => _canHorizontallyScroll;
+ bool IScrollable.CanVerticallyScroll => _canVerticallyScroll;
bool ILogicalScrollable.IsLogicalScrollEnabled => true;
Size ILogicalScrollable.ScrollSize => new(1, 1);
Size ILogicalScrollable.PageScrollSize => new(1, 1);
diff --git a/src/Avalonia.Native/AvnAutomationPeer.cs b/src/Avalonia.Native/AvnAutomationPeer.cs
index e178febd42..86e0c5453d 100644
--- a/src/Avalonia.Native/AvnAutomationPeer.cs
+++ b/src/Avalonia.Native/AvnAutomationPeer.cs
@@ -13,6 +13,14 @@ namespace Avalonia.Native
{
internal class AvnAutomationPeer : NativeCallbackBase, IAvnAutomationPeer
{
+ private static readonly Dictionary s_propertyMap = new()
+ {
+ { AutomationElementIdentifiers.BoundingRectangleProperty, AvnAutomationProperty.AutomationPeer_BoundingRectangle },
+ { AutomationElementIdentifiers.ClassNameProperty, AvnAutomationProperty.AutomationPeer_ClassName },
+ { AutomationElementIdentifiers.NameProperty, AvnAutomationProperty.AutomationPeer_Name },
+ { RangeValuePatternIdentifiers.ValueProperty, AvnAutomationProperty.RangeValueProvider_Value },
+ };
+
private static readonly ConditionalWeakTable s_wrappers = new();
private readonly AutomationPeer _inner;
@@ -20,6 +28,7 @@ namespace Avalonia.Native
{
_inner = inner;
_inner.ChildrenChanged += (_, _) => Node?.ChildrenChanged();
+ _inner.PropertyChanged += OnPeerPropertyChanged;
if (inner is IRootProvider root)
root.FocusChanged += (_, _) => Node?.FocusChanged();
}
@@ -41,6 +50,7 @@ namespace Avalonia.Native
public int HeadingLevel => _inner.GetHeadingLevel();
public IAvnAutomationPeer? Parent => Wrap(_inner.GetParent());
public IAvnAutomationPeer? VisualRoot => Wrap(_inner.GetVisualRoot());
+ public AvnLiveSetting LiveSetting => (AvnLiveSetting)_inner.GetLiveSetting();
public int HasKeyboardFocus() => _inner.HasKeyboardFocus().AsComBool();
public int IsContentElement() => _inner.IsContentElement().AsComBool();
@@ -186,6 +196,12 @@ namespace Avalonia.Native
}
private int IsProvider() => (_inner.GetProvider() is not null).AsComBool();
+
+ private void OnPeerPropertyChanged(object? sender, AutomationPropertyChangedEventArgs e)
+ {
+ if (s_propertyMap.TryGetValue(e.Property, out var property))
+ Node?.PropertyChanged(property);
+ }
}
internal class AvnAutomationPeerArray : NativeCallbackBase, IAvnAutomationPeerArray
diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl
index 2fff3f3794..7aabeceb72 100644
--- a/src/Avalonia.Native/avn.idl
+++ b/src/Avalonia.Native/avn.idl
@@ -652,6 +652,7 @@ enum AvnAutomationControlType
AutomationTable,
AutomationTitleBar,
AutomationSeparator,
+ AutomationExpander,
}
enum AvnLandmarkType
@@ -688,6 +689,13 @@ enum AvnPointerDeviceType
Pen,
}
+enum AvnLiveSetting
+{
+ LiveSettingOff,
+ LiveSettingPolite,
+ LiveSettingAssertive,
+}
+
[uuid(809c652e-7396-11d2-9771-00a0c9b4d50c)]
interface IAvaloniaNativeFactory : IUnknown
{
@@ -1323,6 +1331,8 @@ interface IAvnAutomationPeer : IUnknown
AvnLandmarkType GetLandmarkType();
int GetHeadingLevel();
+
+ AvnLiveSetting GetLiveSetting();
}
[uuid(b00af5da-78af-4b33-bfff-4ce13a6239a9)]
diff --git a/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml b/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
index 3196d262a1..462dfe0323 100644
--- a/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
@@ -66,7 +66,8 @@
BorderThickness="0"
Background="Transparent"
ItemTemplate="{TemplateBinding ItemTemplate}"
- Margin="{DynamicResource AutoCompleteListPadding}" />
+ Margin="{DynamicResource AutoCompleteListPadding}"
+ ScrollViewer.IsScrollChainingEnabled="False" />
diff --git a/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml b/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
index 255cf29133..bcba646461 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
@@ -172,6 +172,7 @@
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
+
+
@@ -91,8 +93,8 @@
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
IsEnabled="{TemplateBinding IsEnabled}"
- MinWidth="{DynamicResource DatePickerThemeMinWidth}"
- MaxWidth="{DynamicResource DatePickerThemeMaxWidth}"
+ MinWidth="{TemplateBinding MinWidth}"
+ MaxWidth="{TemplateBinding MaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
TemplatedControl.IsTemplateFocusTarget="True">
diff --git a/src/Avalonia.Themes.Fluent/Controls/MenuScrollViewer.xaml b/src/Avalonia.Themes.Fluent/Controls/MenuScrollViewer.xaml
index 9dd65b1349..8badfa98eb 100644
--- a/src/Avalonia.Themes.Fluent/Controls/MenuScrollViewer.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/MenuScrollViewer.xaml
@@ -21,6 +21,7 @@
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/OverlayPopupHost.xaml b/src/Avalonia.Themes.Fluent/Controls/OverlayPopupHost.xaml
index 598ec994fc..3b1b5f6c3d 100644
--- a/src/Avalonia.Themes.Fluent/Controls/OverlayPopupHost.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/OverlayPopupHost.xaml
@@ -7,6 +7,7 @@
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml b/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
index e818b4c382..cd3942738c 100644
--- a/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
@@ -9,6 +9,7 @@
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/ScrollBar.xaml b/src/Avalonia.Themes.Fluent/Controls/ScrollBar.xaml
index 1107bf2c27..8af22dd0b9 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ScrollBar.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ScrollBar.xaml
@@ -137,7 +137,8 @@
Grid.Row="0"
Focusable="False"
MinWidth="{DynamicResource ScrollBarSize}"
- Height="{DynamicResource ScrollBarSize}">
+ Height="{DynamicResource ScrollBarSize}"
+ AutomationProperties.Name="Line up">
@@ -155,19 +156,22 @@
+ Focusable="False"
+ AutomationProperties.Name="Page up"/>
+ Focusable="False"
+ AutomationProperties.Name="Page down"/>
+ RenderTransformOrigin="100%,50%"
+ AutomationProperties.Name="Position"/>
+ Height="{DynamicResource ScrollBarSize}"
+ AutomationProperties.Name="Line down">
@@ -215,7 +220,8 @@
Grid.Column="0"
Focusable="False"
MinHeight="{DynamicResource ScrollBarSize}"
- Width="{DynamicResource ScrollBarSize}">
+ Width="{DynamicResource ScrollBarSize}"
+ AutomationProperties.Name="Column left">
@@ -232,19 +238,22 @@
+ Focusable="False"
+ AutomationProperties.Name="Page left"/>
+ Focusable="False"
+ AutomationProperties.Name="Page right"/>
+ RenderTransformOrigin="50%,100%"
+ AutomationProperties.Name="Position"/>
+ Width="{DynamicResource ScrollBarSize}"
+ AutomationProperties.Name="Column right">
diff --git a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
index 7eaa4bb307..27e52fa152 100644
--- a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
@@ -78,6 +78,8 @@
+
+
@@ -90,8 +92,8 @@
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
IsEnabled="{TemplateBinding IsEnabled}"
- MinWidth="{DynamicResource TimePickerThemeMinWidth}"
- MaxWidth="{DynamicResource TimePickerThemeMaxWidth}"
+ MinWidth="{TemplateBinding MinWidth}"
+ MaxWidth="{TemplateBinding MaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
diff --git a/src/Avalonia.Themes.Simple/Controls/AutoCompleteBox.xaml b/src/Avalonia.Themes.Simple/Controls/AutoCompleteBox.xaml
index 10b48a12f6..5b760ba14e 100644
--- a/src/Avalonia.Themes.Simple/Controls/AutoCompleteBox.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/AutoCompleteBox.xaml
@@ -38,6 +38,7 @@
BorderThickness="0"
Foreground="{TemplateBinding Foreground}"
ItemTemplate="{TemplateBinding ItemTemplate}"
+ ScrollViewer.IsScrollChainingEnabled="False"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
diff --git a/src/Avalonia.Themes.Simple/Controls/ComboBox.xaml b/src/Avalonia.Themes.Simple/Controls/ComboBox.xaml
index 54e75db0a2..5a6266af6e 100644
--- a/src/Avalonia.Themes.Simple/Controls/ComboBox.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/ComboBox.xaml
@@ -87,7 +87,8 @@
BorderThickness="1">
+ IsDeferredScrollingEnabled="{TemplateBinding (ScrollViewer.IsDeferredScrollingEnabled)}"
+ ScrollViewer.IsScrollChainingEnabled="False">
diff --git a/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml b/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml
index c70721aac7..6e2f41cf2c 100644
--- a/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/OverlayPopupHost.xaml
@@ -6,6 +6,9 @@
+
+
+
diff --git a/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml b/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml
index aaf51a2cef..d4e8d252eb 100644
--- a/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/PopupRoot.xaml
@@ -8,6 +8,9 @@
+
+
+
diff --git a/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml b/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml
index e8dfd3736f..a7f11ec24c 100644
--- a/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/ScrollBar.xaml
@@ -18,7 +18,8 @@
MinWidth="{DynamicResource ScrollBarThickness}"
VerticalAlignment="Center"
Classes="repeat"
- Focusable="False">
+ Focusable="False"
+ AutomationProperties.Name="Column left">
+ Focusable="False"
+ AutomationProperties.Name="Column right">
@@ -68,7 +73,8 @@
MinHeight="{DynamicResource ScrollBarThickness}"
HorizontalAlignment="Center"
Classes="repeat"
- Focusable="False">
+ Focusable="False"
+ AutomationProperties.Name="Line up">
+ Focusable="False"
+ AutomationProperties.Name="Line down">
diff --git a/src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml b/src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml
index ea62f757c5..f691ff6651 100644
--- a/src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/ScrollViewer.xaml
@@ -40,6 +40,7 @@
+
diff --git a/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs b/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs
index f854e922f8..91495ea0ea 100644
--- a/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs
+++ b/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs
@@ -1,10 +1,7 @@
using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.JavaScript;
-using System.Threading;
using System.Threading.Tasks;
using Avalonia.Browser.Interop;
@@ -19,11 +16,14 @@ internal partial class RenderWorker
private static partial void InitializeRenderTargets();
internal static int WorkerThreadId;
+
+ // The worker task needs to be rooted otherwise the web worker will exit.
+ private static Task? s_workerTask;
public static Task InitializeAsync()
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
- var workerTask = JSWebWorkerClone.RunAsync(async () =>
+ s_workerTask = JSWebWorkerRunAsync(null, async () =>
{
try
{
@@ -41,103 +41,18 @@ internal partial class RenderWorker
}
});
- workerTask.ContinueWith(_ =>
+ s_workerTask.ContinueWith(_ =>
{
- if (workerTask.IsFaulted)
- tcs.TrySetException(workerTask.Exception);
+ if (s_workerTask.IsFaulted)
+ tcs.TrySetException(s_workerTask.Exception);
});
return tcs.Task;
}
- public static class JSWebWorkerClone
- {
- private static readonly MethodInfo _setExtLoop;
- private static readonly MethodInfo _intallInterop;
-
- [DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Runtime.InteropServices.JavaScript.JSSynchronizationContext",
- "System.Runtime.InteropServices.JavaScript")]
- [DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Runtime.InteropServices.JavaScript.JSHostImplementation",
- "System.Runtime.InteropServices.JavaScript")]
- [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Private runtime API")]
- [UnconditionalSuppressMessage("Trimming", "IL2036", Justification = "Private runtime API")]
- [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Private runtime API")]
- [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "Private runtime API")]
- static JSWebWorkerClone()
- {
- var syncContext = typeof(System.Runtime.InteropServices.JavaScript.JSHost)
- .Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSSynchronizationContext")!;
- var hostImpl = typeof(System.Runtime.InteropServices.JavaScript.JSHost)
- .Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSHostImplementation")!;
-
- _setExtLoop = hostImpl.GetMethod("SetHasExternalEventLoop")!;
- _intallInterop = syncContext.GetMethod("InstallWebWorkerInterop")!;
- }
-
- public static Task RunAsync(Func run)
- {
- var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
- var th = new Thread(_ =>
- {
- _intallInterop.Invoke(null, [false, CancellationToken.None]);
- try
- {
- run().ContinueWith(t =>
- {
- if (t.IsFaulted)
- tcs.TrySetException(t.Exception);
- else if (t.IsCanceled)
- tcs.TrySetCanceled();
- else
- tcs.TrySetResult();
- });
- }
- catch(Exception e)
- {
- tcs.TrySetException(e);
- }
- })
- {
- Name = "Manual JS worker"
- };
- _setExtLoop.Invoke(null, [th]);
-#pragma warning disable CA1416
- th.Start();
-#pragma warning restore CA1416
- return tcs.Task;
- }
-
- }
-
- // TODO: Use this class instead of JSWebWorkerClone once https://github.com/dotnet/runtime/issues/102010 is fixed
- // TODO12: It was fixed in .NET 10
- class JSWebWorkerWrapper
- {
- [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.JSWebWorker",
- "System.Runtime.InteropServices.JavaScript")]
- [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Private runtime API")]
- [UnconditionalSuppressMessage("Trimming", "IL2036", Justification = "Private runtime API")]
- [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Private runtime API")]
- [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "Private runtime API")]
- static JSWebWorkerWrapper()
- {
- var type = typeof(System.Runtime.InteropServices.JavaScript.JSHost)
- .Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSWebWorker");
-#pragma warning disable IL2075
- var m = type!
-
- .GetMethods(BindingFlags.Static | BindingFlags.Public
- ).First(m => m.Name == "RunAsync"
- && m.ReturnType == typeof(Task)
- && m.GetParameters() is { } parameters
- && parameters.Length == 1
- && parameters[0].ParameterType == typeof(Func));
-
-#pragma warning restore IL2075
- RunAsync = (Func, Task>) Delegate.CreateDelegate(typeof(Func, Task>), m);
-
- }
-
- public static Func, Task> RunAsync { get; set; }
- }
+ // Even though this API is public in the .NET code, it's not part of ref assemblies and is not a stable API.
+ [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RunAsync")]
+ private static extern Task JSWebWorkerRunAsync(
+ [UnsafeAccessorType("System.Runtime.InteropServices.JavaScript.JSWebWorker, System.Runtime.InteropServices.JavaScript")] object? instance,
+ Func body);
}
diff --git a/src/HarfBuzz/Avalonia.HarfBuzz/Avalonia.HarfBuzz.csproj b/src/HarfBuzz/Avalonia.HarfBuzz/Avalonia.HarfBuzz.csproj
index a528326db9..788886f3a9 100644
--- a/src/HarfBuzz/Avalonia.HarfBuzz/Avalonia.HarfBuzz.csproj
+++ b/src/HarfBuzz/Avalonia.HarfBuzz/Avalonia.HarfBuzz.csproj
@@ -4,8 +4,6 @@
true
true
true
-
- $(WarningsAsErrors);CS0618
diff --git a/src/Headless/Avalonia.Headless.XUnit/Avalonia.Headless.XUnit.csproj b/src/Headless/Avalonia.Headless.XUnit/Avalonia.Headless.XUnit.csproj
index 12f890c744..4ed3d6674e 100644
--- a/src/Headless/Avalonia.Headless.XUnit/Avalonia.Headless.XUnit.csproj
+++ b/src/Headless/Avalonia.Headless.XUnit/Avalonia.Headless.XUnit.csproj
@@ -5,8 +5,7 @@
-
-
+
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaDelayEnumeratedTheoryTestCase.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaDelayEnumeratedTheoryTestCase.cs
new file mode 100644
index 0000000000..f2f9bb3b38
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaDelayEnumeratedTheoryTestCase.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Threading;
+using Xunit.Sdk;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+internal sealed class AvaloniaDelayEnumeratedTheoryTestCase
+ : XunitDelayEnumeratedTheoryTestCase, ISelfExecutingXunitTestCase
+{
+ public AvaloniaDelayEnumeratedTheoryTestCase(
+ IXunitTestMethod testMethod,
+ string testCaseDisplayName,
+ string uniqueID,
+ bool @explicit,
+ bool skipTestWithoutData,
+ Type[]? skipExceptions = null,
+ string? skipReason = null,
+ Type? skipType = null,
+ string? skipUnless = null,
+ string? skipWhen = null,
+ Dictionary>? traits = null,
+ string? sourceFilePath = null,
+ int? sourceLineNumber = null,
+ int? timeout = null)
+ : base(
+ testMethod,
+ testCaseDisplayName,
+ uniqueID,
+ @explicit,
+ skipTestWithoutData,
+ skipExceptions,
+ skipReason,
+ skipType,
+ skipUnless,
+ skipWhen,
+ traits,
+ sourceFilePath,
+ sourceLineNumber,
+ timeout)
+ {
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
+ public AvaloniaDelayEnumeratedTheoryTestCase()
+ {
+ }
+
+ public async ValueTask Run(
+ ExplicitOption explicitOption,
+ IMessageBus messageBus,
+ object?[] constructorArguments,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource)
+ {
+ var tests = await aggregator.RunAsync(CreateTests, []);
+
+ // We need to block the XUnit thread to ensure its concurrency throttle is effective.
+ // See https://github.com/AArnott/Xunit.StaFact/pull/55#issuecomment-826187354 for details.
+ var runSummary = Task.Run(async () => await AvaloniaTestCaseRunner.Instance.Run(
+ this,
+ tests,
+ messageBus,
+ aggregator,
+ cancellationTokenSource,
+ TestCaseDisplayName,
+ SkipReason,
+ explicitOption,
+ constructorArguments))
+ .GetAwaiter()
+ .GetResult();
+
+ return runSummary;
+ }
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaFact.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaFact.cs
index f501fc7a56..08b0984821 100644
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaFact.cs
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaFact.cs
@@ -1,9 +1,7 @@
using System;
-using System.ComponentModel;
-using System.Threading;
+using System.Runtime.CompilerServices;
using Xunit;
-using Xunit.Abstractions;
-using Xunit.Sdk;
+using Xunit.v3;
namespace Avalonia.Headless.XUnit;
@@ -12,24 +10,8 @@ namespace Avalonia.Headless.XUnit;
/// such that awaited expressions resume on the test's "main thread".
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
-[XunitTestCaseDiscoverer("Avalonia.Headless.XUnit.AvaloniaUIFactDiscoverer", "Avalonia.Headless.XUnit")]
-public sealed class AvaloniaFactAttribute : FactAttribute
-{
-
-}
-
-[EditorBrowsable(EditorBrowsableState.Never)]
-public class AvaloniaUIFactDiscoverer : FactDiscoverer
-{
- private readonly IMessageSink diagnosticMessageSink;
- public AvaloniaUIFactDiscoverer(IMessageSink diagnosticMessageSink)
- : base(diagnosticMessageSink)
- {
- this.diagnosticMessageSink = diagnosticMessageSink;
- }
-
- protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
- {
- return new AvaloniaTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod);
- }
-}
+[XunitTestCaseDiscoverer(typeof(AvaloniaFactDiscoverer))]
+public sealed class AvaloniaFactAttribute(
+ [CallerFilePath] string? sourceFilePath = null,
+ [CallerLineNumber] int sourceLineNumber = -1)
+ : FactAttribute(sourceFilePath, sourceLineNumber);
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaFactDiscoverer.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaFactDiscoverer.cs
new file mode 100644
index 0000000000..5c8e971e18
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaFactDiscoverer.cs
@@ -0,0 +1,34 @@
+using System;
+using System.ComponentModel;
+using Xunit.Internal;
+using Xunit.Sdk;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+[EditorBrowsable(EditorBrowsableState.Never)]
+public class AvaloniaFactDiscoverer : FactDiscoverer
+{
+ protected override IXunitTestCase CreateTestCase(
+ ITestFrameworkDiscoveryOptions discoveryOptions,
+ IXunitTestMethod testMethod,
+ IFactAttribute factAttribute)
+ {
+ var details = TestIntrospectionHelper.GetTestCaseDetails(discoveryOptions, testMethod, factAttribute);
+
+ return new AvaloniaTestCase(
+ details.ResolvedTestMethod,
+ details.TestCaseDisplayName,
+ details.UniqueID,
+ details.Explicit,
+ details.SkipExceptions,
+ details.SkipReason,
+ details.SkipType,
+ details.SkipUnless,
+ details.SkipWhen,
+ testMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase),
+ sourceFilePath: details.SourceFilePath,
+ sourceLineNumber: details.SourceLineNumber,
+ timeout: details.Timeout);
+ }
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestAssemblyRunner.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestAssemblyRunner.cs
deleted file mode 100644
index 4b1cf84914..0000000000
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestAssemblyRunner.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Threading;
-using System.Threading.Tasks;
-using Avalonia.Threading;
-using Xunit.Abstractions;
-using Xunit.Sdk;
-
-namespace Avalonia.Headless.XUnit;
-
-internal class AvaloniaTestAssemblyRunner : XunitTestAssemblyRunner
-{
- private HeadlessUnitTestSession? _session;
-
- public AvaloniaTestAssemblyRunner(ITestAssembly testAssembly, IEnumerable testCases,
- IMessageSink diagnosticMessageSink, IMessageSink executionMessageSink,
- ITestFrameworkExecutionOptions executionOptions) : base(testAssembly, testCases, diagnosticMessageSink,
- executionMessageSink, executionOptions)
- {
- }
-
- protected override void SetupSyncContext(int maxParallelThreads)
- {
- _session = HeadlessUnitTestSession.GetOrStartForAssembly(
- Assembly.Load(new AssemblyName(TestAssembly.Assembly.Name)));
- base.SetupSyncContext(1);
- }
-
- public override void Dispose()
- {
- _session?.Dispose();
- base.Dispose();
- }
-
- protected override Task RunTestCollectionAsync(
- IMessageBus messageBus,
- ITestCollection testCollection,
- IEnumerable testCases,
- CancellationTokenSource cancellationTokenSource)
- {
- return new AvaloniaTestCollectionRunner(_session!, testCollection, testCases, DiagnosticMessageSink, messageBus,
- TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource).RunAsync();
- }
-
- private class AvaloniaTestCollectionRunner : XunitTestCollectionRunner
- {
- private readonly HeadlessUnitTestSession _session;
-
- public AvaloniaTestCollectionRunner(HeadlessUnitTestSession session,
- ITestCollection testCollection, IEnumerable testCases,
- IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer,
- ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) : base(testCollection,
- testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource)
- {
- _session = session;
- }
-
- protected override Task RunTestClassAsync(
- ITestClass testClass,
- IReflectionTypeInfo @class,
- IEnumerable testCases)
- {
- return new AvaloniaTestClassRunner(_session, testClass, @class, testCases, DiagnosticMessageSink, MessageBus,
- TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource,
- CollectionFixtureMappings).RunAsync();
- }
- }
-
- private class AvaloniaTestClassRunner : XunitTestClassRunner
- {
- private readonly HeadlessUnitTestSession _session;
-
- public AvaloniaTestClassRunner(HeadlessUnitTestSession session, ITestClass testClass,
- IReflectionTypeInfo @class,
- IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus,
- ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator,
- CancellationTokenSource cancellationTokenSource, IDictionary collectionFixtureMappings) :
- base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator,
- cancellationTokenSource, collectionFixtureMappings)
- {
- _session = session;
- }
-
- protected override Task RunTestMethodAsync(
- ITestMethod testMethod,
- IReflectionMethodInfo method,
- IEnumerable testCases,
- object[] constructorArguments)
- {
- return new AvaloniaTestMethodRunner(_session, testMethod, Class, method, testCases, DiagnosticMessageSink,
- MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource,
- constructorArguments).RunAsync();
- }
- }
-
- private class AvaloniaTestMethodRunner : XunitTestMethodRunner
- {
- private readonly HeadlessUnitTestSession _session;
- private readonly IMessageBus _messageBus;
- private readonly ExceptionAggregator _aggregator;
- private readonly CancellationTokenSource _cancellationTokenSource;
- private readonly object[] _constructorArguments;
-
- public AvaloniaTestMethodRunner(HeadlessUnitTestSession session, ITestMethod testMethod,
- IReflectionTypeInfo @class,
- IReflectionMethodInfo method, IEnumerable testCases, IMessageSink diagnosticMessageSink,
- IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource,
- object[] constructorArguments) : base(testMethod, @class, method, testCases, diagnosticMessageSink,
- messageBus, aggregator, cancellationTokenSource, constructorArguments)
- {
- _session = session;
- _messageBus = messageBus;
- _aggregator = aggregator;
- _cancellationTokenSource = cancellationTokenSource;
- _constructorArguments = constructorArguments;
- }
-
- protected override Task RunTestCaseAsync(IXunitTestCase testCase)
- {
- return AvaloniaTestCaseRunner.RunTest(_session, testCase, testCase.DisplayName, testCase.SkipReason,
- _constructorArguments, testCase.TestMethodArguments, _messageBus, _aggregator,
- _cancellationTokenSource);
- }
- }
-}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCase.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCase.cs
index c620397dd5..a0a73c2c06 100644
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCase.cs
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCase.cs
@@ -1,20 +1,46 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
-using Xunit.Abstractions;
+using Avalonia.Threading;
using Xunit.Sdk;
+using Xunit.v3;
namespace Avalonia.Headless.XUnit;
-internal class AvaloniaTestCase : XunitTestCase
+internal sealed class AvaloniaTestCase : XunitTestCase, ISelfExecutingXunitTestCase
{
public AvaloniaTestCase(
- IMessageSink diagnosticMessageSink,
- TestMethodDisplay defaultMethodDisplay,
- ITestMethod testMethod,
- object?[]? testMethodArguments = null)
- : base(diagnosticMessageSink, defaultMethodDisplay, TestMethodDisplayOptions.None, testMethod, testMethodArguments)
+ IXunitTestMethod testMethod,
+ string testCaseDisplayName,
+ string uniqueID,
+ bool @explicit,
+ Type[]? skipExceptions = null,
+ string? skipReason = null,
+ Type? skipType = null,
+ string? skipUnless = null,
+ string? skipWhen = null,
+ Dictionary>? traits = null,
+ object?[]? testMethodArguments = null,
+ string? sourceFilePath = null,
+ int? sourceLineNumber = null,
+ int? timeout = null)
+ : base(
+ testMethod,
+ testCaseDisplayName,
+ uniqueID,
+ @explicit,
+ skipExceptions,
+ skipReason,
+ skipType,
+ skipUnless,
+ skipWhen,
+ traits,
+ testMethodArguments,
+ sourceFilePath,
+ sourceLineNumber,
+ timeout)
{
}
@@ -24,23 +50,30 @@ internal class AvaloniaTestCase : XunitTestCase
{
}
- public override Task RunAsync(
- IMessageSink diagnosticMessageSink,
+ public async ValueTask Run(
+ ExplicitOption explicitOption,
IMessageBus messageBus,
- object[] constructorArguments,
+ object?[] constructorArguments,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
{
- var session = HeadlessUnitTestSession.GetOrStartForAssembly(Method.ToRuntimeMethod().DeclaringType?.Assembly);
+ var tests = await aggregator.RunAsync(CreateTests, []);
// We need to block the XUnit thread to ensure its concurrency throttle is effective.
// See https://github.com/AArnott/Xunit.StaFact/pull/55#issuecomment-826187354 for details.
- var runSummary =
- Task.Run(() => AvaloniaTestCaseRunner.RunTest(session, this, DisplayName, SkipReason, constructorArguments,
- TestMethodArguments, messageBus, aggregator, cancellationTokenSource))
+ var runSummary = Task.Run(async () => await AvaloniaTestCaseRunner.Instance.Run(
+ this,
+ tests,
+ messageBus,
+ aggregator,
+ cancellationTokenSource,
+ TestCaseDisplayName,
+ SkipReason,
+ explicitOption,
+ constructorArguments))
.GetAwaiter()
.GetResult();
- return Task.FromResult(runSummary);
+ return runSummary;
}
}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunner.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunner.cs
index 79b564f11d..7a52cf97c0 100644
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunner.cs
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunner.cs
@@ -1,103 +1,59 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using Avalonia.Threading;
-using Xunit.Abstractions;
using Xunit.Sdk;
+using Xunit.v3;
namespace Avalonia.Headless.XUnit;
-internal class AvaloniaTestCaseRunner : XunitTestCaseRunner
+internal sealed class AvaloniaTestCaseRunner
+ : XunitTestCaseRunnerBase
{
- private readonly HeadlessUnitTestSession _session;
- private readonly Action? _onAfterTestInvoked;
+ public static AvaloniaTestCaseRunner Instance { get; } = new();
- public AvaloniaTestCaseRunner(
- HeadlessUnitTestSession session, Action? onAfterTestInvoked,
- IXunitTestCase testCase, string displayName, string skipReason, object[] constructorArguments,
- object[] testMethodArguments, IMessageBus messageBus, ExceptionAggregator aggregator,
- CancellationTokenSource cancellationTokenSource) : base(testCase, displayName, skipReason, constructorArguments,
- testMethodArguments, messageBus, aggregator, cancellationTokenSource)
+ private AvaloniaTestCaseRunner()
{
- _session = session;
- _onAfterTestInvoked = onAfterTestInvoked;
}
- public static Task RunTest(HeadlessUnitTestSession session,
- IXunitTestCase testCase, string displayName, string skipReason, object[] constructorArguments,
- object[] testMethodArguments, IMessageBus messageBus, ExceptionAggregator aggregator,
- CancellationTokenSource cancellationTokenSource)
+ public async ValueTask Run(
+ IXunitTestCase testCase,
+ IReadOnlyCollection tests,
+ IMessageBus messageBus,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource,
+ string displayName,
+ string? skipReason,
+ ExplicitOption explicitOption,
+ object?[] constructorArguments)
{
- var afterTest = () => Dispatcher.UIThread.RunJobs();
-
- var runner = new AvaloniaTestCaseRunner(session, afterTest, testCase, displayName,
- skipReason, constructorArguments, testMethodArguments, messageBus, aggregator, cancellationTokenSource);
- return runner.RunAsync();
- }
-
- protected override XunitTestRunner CreateTestRunner(ITest test, IMessageBus messageBus, Type testClass,
- object[] constructorArguments,
- MethodInfo testMethod, object[] testMethodArguments, string skipReason,
- IReadOnlyList beforeAfterAttributes,
- ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
- {
- return new AvaloniaTestRunner(_session, _onAfterTestInvoked, test, messageBus, testClass, constructorArguments,
- testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource);
- }
-
- private class AvaloniaTestRunner : XunitTestRunner
- {
- private readonly HeadlessUnitTestSession _session;
- private readonly Action? _onAfterTestInvoked;
-
- public AvaloniaTestRunner(
- HeadlessUnitTestSession session, Action? onAfterTestInvoked,
- ITest test, IMessageBus messageBus, Type testClass, object[] constructorArguments, MethodInfo testMethod,
- object[] testMethodArguments, string skipReason,
- IReadOnlyList beforeAfterAttributes, ExceptionAggregator aggregator,
- CancellationTokenSource cancellationTokenSource) : base(test, messageBus, testClass, constructorArguments,
- testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource)
- {
- _session = session;
- _onAfterTestInvoked = onAfterTestInvoked;
- }
-
- protected override Task InvokeTestMethodAsync(ExceptionAggregator aggregator)
- {
- return _session.Dispatch(
- () => new AvaloniaTestInvoker(_onAfterTestInvoked, Test, MessageBus, TestClass,
- ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator,
- CancellationTokenSource).RunAsync(),
- CancellationTokenSource.Token);
- }
+ var session = HeadlessUnitTestSession.GetOrStartForAssembly(testCase.TestClass.Class.Assembly);
+
+ await using var ctxt = new AvaloniaTestCaseRunnerContext(
+ testCase,
+ tests,
+ messageBus,
+ aggregator,
+ cancellationTokenSource,
+ displayName,
+ skipReason,
+ explicitOption,
+ constructorArguments,
+ session);
+ await ctxt.InitializeAsync();
+
+ return await Run(ctxt);
}
- private class AvaloniaTestInvoker : XunitTestInvoker
- {
- private readonly Action? _onAfterTestInvoked;
-
- public AvaloniaTestInvoker(
- Action? onAfterTestInvoked,
- ITest test, IMessageBus messageBus, Type testClass, object[] constructorArguments, MethodInfo testMethod,
- object[] testMethodArguments, IReadOnlyList beforeAfterAttributes,
- ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) : base(test, messageBus,
- testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator,
- cancellationTokenSource)
- {
- _onAfterTestInvoked = onAfterTestInvoked;
- }
-
- protected override async Task AfterTestMethodInvokedAsync()
- {
- await base.AfterTestMethodInvokedAsync();
-
- // Only here we can execute random code after the test, where exception will be properly handled by the XUnit.
- if (_onAfterTestInvoked is not null)
- {
- Aggregator.Run(_onAfterTestInvoked);
- }
- }
- }
+ protected override ValueTask RunTest(
+ AvaloniaTestCaseRunnerContext ctxt,
+ IXunitTest test)
+ => AvaloniaTestRunner.Instance.Run(
+ test,
+ ctxt.MessageBus,
+ ctxt.ConstructorArguments,
+ ctxt.ExplicitOption,
+ ctxt.Aggregator.Clone(),
+ ctxt.CancellationTokenSource,
+ ctxt.BeforeAfterTestAttributes,
+ ctxt.Session);
}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunnerContext.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunnerContext.cs
new file mode 100644
index 0000000000..2c8decf9da
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestCaseRunnerContext.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Threading;
+using Xunit.Sdk;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+internal sealed class AvaloniaTestCaseRunnerContext(
+ IXunitTestCase testCase,
+ IReadOnlyCollection tests,
+ IMessageBus messageBus,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource,
+ string displayName,
+ string? skipReason,
+ ExplicitOption explicitOption,
+ object?[] constructorArguments,
+ HeadlessUnitTestSession session)
+ : XunitTestCaseRunnerContext(
+ testCase,
+ tests,
+ messageBus,
+ aggregator,
+ cancellationTokenSource,
+ displayName,
+ skipReason,
+ explicitOption,
+ constructorArguments)
+{
+ public HeadlessUnitTestSession Session { get; } = session;
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFramework.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFramework.cs
index aa9b3e7e18..61db27755b 100644
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFramework.cs
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFramework.cs
@@ -1,35 +1,13 @@
-using System.Collections.Generic;
-using System.Reflection;
-using Xunit.Abstractions;
-using Xunit.Sdk;
+using System.Reflection;
+using Xunit.v3;
namespace Avalonia.Headless.XUnit;
-internal class AvaloniaTestFramework : XunitTestFramework
+internal sealed class AvaloniaTestFramework : XunitTestFramework
{
- public AvaloniaTestFramework(IMessageSink messageSink) : base(messageSink)
- {
- }
+ protected override ITestFrameworkDiscoverer CreateDiscoverer(Assembly assembly)
+ => new AvaloniaTestFrameworkDiscoverer(new XunitTestAssembly(assembly, null, assembly.GetName().Version));
- protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
- => new Executor(assemblyName, SourceInformationProvider, DiagnosticMessageSink);
-
-
- private class Executor : XunitTestFrameworkExecutor
- {
- public Executor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider,
- IMessageSink diagnosticMessageSink) : base(assemblyName, sourceInformationProvider,
- diagnosticMessageSink)
- {
- }
-
- protected override async void RunTestCases(IEnumerable testCases,
- IMessageSink executionMessageSink,
- ITestFrameworkExecutionOptions executionOptions)
- {
- using (var assemblyRunner = new AvaloniaTestAssemblyRunner(
- TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink,
- executionOptions)) await assemblyRunner.RunAsync();
- }
- }
+ protected override ITestFrameworkExecutor CreateExecutor(Assembly assembly)
+ => new AvaloniaTestFrameworkExecutor(new XunitTestAssembly(assembly, null, assembly.GetName().Version));
}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkAttribute.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkAttribute.cs
index bdd8f3b0ea..7e33adfbfb 100644
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkAttribute.cs
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkAttribute.cs
@@ -1,8 +1,5 @@
using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using Xunit.Abstractions;
-using Xunit.Sdk;
+using Xunit.v3;
namespace Avalonia.Headless.XUnit;
@@ -12,27 +9,9 @@ namespace Avalonia.Headless.XUnit;
///
/// It is an alternative to using [AvaloniaFact] or [AvaloniaTheory] attributes on every test method.
///
-[TestFrameworkDiscoverer("Avalonia.Headless.XUnit.AvaloniaTestFrameworkTypeDiscoverer", "Avalonia.Headless.XUnit")]
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public sealed class AvaloniaTestFrameworkAttribute : Attribute, ITestFrameworkAttribute
{
-}
-
-///
-/// Discoverer implementation for the Avalonia testing framework.
-///
-public class AvaloniaTestFrameworkTypeDiscoverer : ITestFrameworkTypeDiscoverer
-{
- ///
- /// Creates instance of .
- ///
- public AvaloniaTestFrameworkTypeDiscoverer(IMessageSink _)
- {
- }
-
- ///
- public Type GetTestFrameworkType(IAttributeInfo attribute)
- {
- return typeof(AvaloniaTestFramework);
- }
+ public Type FrameworkType
+ => typeof(AvaloniaTestFramework);
}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkDiscoverer.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkDiscoverer.cs
new file mode 100644
index 0000000000..e29498452b
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkDiscoverer.cs
@@ -0,0 +1,16 @@
+using Xunit;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+internal sealed class AvaloniaTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer
+{
+ public AvaloniaTestFrameworkDiscoverer(
+ IXunitTestAssembly testAssembly,
+ IXunitTestCollectionFactory? collectionFactory = null)
+ : base(testAssembly, collectionFactory)
+ {
+ DiscovererTypeCache[typeof(FactAttribute)] = typeof(AvaloniaFactDiscoverer);
+ DiscovererTypeCache[typeof(TheoryAttribute)] = typeof(AvaloniaTheoryDiscoverer);
+ }
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkExecutor.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkExecutor.cs
new file mode 100644
index 0000000000..348a718b4b
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestFrameworkExecutor.cs
@@ -0,0 +1,19 @@
+using System.Threading.Tasks;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+internal sealed class AvaloniaTestFrameworkExecutor(IXunitTestAssembly testAssembly)
+ : XunitTestFrameworkExecutor(testAssembly)
+{
+ private readonly HeadlessUnitTestSession _session = HeadlessUnitTestSession.GetOrStartForAssembly(testAssembly.Assembly);
+
+ protected override ITestFrameworkDiscoverer CreateDiscoverer()
+ => new AvaloniaTestFrameworkDiscoverer(TestAssembly);
+
+ public override async ValueTask DisposeAsync()
+ {
+ await _session.DisposeAsync();
+ await base.DisposeAsync();
+ }
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestRunner.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestRunner.cs
new file mode 100644
index 0000000000..ad3c33028b
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestRunner.cs
@@ -0,0 +1,50 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Threading;
+using Xunit.Sdk;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+internal sealed class AvaloniaTestRunner : XunitTestRunnerBase
+{
+ public static AvaloniaTestRunner Instance { get; } = new();
+
+ private AvaloniaTestRunner()
+ {
+ }
+
+ public async ValueTask Run(
+ IXunitTest test,
+ IMessageBus messageBus,
+ object?[] constructorArguments,
+ ExplicitOption explicitOption,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource,
+ IReadOnlyCollection beforeAfterAttributes,
+ HeadlessUnitTestSession session)
+ {
+ await using var ctxt = new AvaloniaTestRunnerContext(
+ test,
+ messageBus,
+ explicitOption,
+ aggregator,
+ cancellationTokenSource,
+ beforeAfterAttributes,
+ constructorArguments,
+ session
+ );
+ await ctxt.InitializeAsync();
+
+ return await session.Dispatch(
+ async () =>
+ {
+ var dispatcher = Dispatcher.UIThread;
+ var summary = await Run(ctxt);
+ dispatcher.RunJobs();
+ return summary;
+ },
+ ctxt.CancellationTokenSource.Token);
+ }
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestRunnerContext.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestRunnerContext.cs
new file mode 100644
index 0000000000..137e8c3477
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTestRunnerContext.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading;
+using Xunit.Sdk;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+internal sealed class AvaloniaTestRunnerContext(
+ IXunitTest test,
+ IMessageBus messageBus,
+ ExplicitOption explicitOption,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource,
+ IReadOnlyCollection beforeAfterTestAttributes,
+ object?[] constructorArguments,
+ HeadlessUnitTestSession session)
+ : XunitTestRunnerContext(
+ test,
+ messageBus,
+ explicitOption,
+ aggregator,
+ cancellationTokenSource,
+ beforeAfterTestAttributes,
+ constructorArguments)
+{
+ public HeadlessUnitTestSession Session { get; } = session;
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryAttribute.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryAttribute.cs
index 53c997f08f..86bdf0bfae 100644
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryAttribute.cs
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryAttribute.cs
@@ -1,9 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.ComponentModel;
using Xunit;
-using Xunit.Abstractions;
-using Xunit.Sdk;
+using Xunit.v3;
namespace Avalonia.Headless.XUnit;
@@ -12,26 +9,5 @@ namespace Avalonia.Headless.XUnit;
/// such that awaited expressions resume on the test's "main thread".
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
-[XunitTestCaseDiscoverer("Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer", "Avalonia.Headless.XUnit")]
-public sealed class AvaloniaTheoryAttribute : TheoryAttribute
-{
-}
-
-[EditorBrowsable(EditorBrowsableState.Never)]
-public class AvaloniaTheoryDiscoverer : TheoryDiscoverer
-{
- public AvaloniaTheoryDiscoverer(IMessageSink diagnosticMessageSink)
- : base(diagnosticMessageSink)
- {
- }
-
- protected override IEnumerable CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
- {
- yield return new AvaloniaTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow);
- }
-
- protected override IEnumerable CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
- {
- yield return new AvaloniaTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod);
- }
-}
+[XunitTestCaseDiscoverer(typeof(AvaloniaTheoryDiscoverer))]
+public sealed class AvaloniaTheoryAttribute : TheoryAttribute;
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryDiscoverer.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryDiscoverer.cs
new file mode 100644
index 0000000000..a56891beed
--- /dev/null
+++ b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryDiscoverer.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Internal;
+using Xunit.Sdk;
+using Xunit.v3;
+
+namespace Avalonia.Headless.XUnit;
+
+[EditorBrowsable(EditorBrowsableState.Never)]
+public class AvaloniaTheoryDiscoverer : TheoryDiscoverer
+{
+ protected override ValueTask> CreateTestCasesForDataRow(
+ ITestFrameworkDiscoveryOptions discoveryOptions,
+ IXunitTestMethod testMethod,
+ ITheoryAttribute theoryAttribute,
+ ITheoryDataRow dataRow,
+ object?[] testMethodArguments)
+ {
+ var details = TestIntrospectionHelper.GetTestCaseDetailsForTheoryDataRow(
+ discoveryOptions,
+ testMethod,
+ theoryAttribute,
+ dataRow,
+ testMethodArguments);
+ var traits = TestIntrospectionHelper.GetTraits(testMethod, dataRow);
+
+ var testCase = new AvaloniaTestCase(
+ details.ResolvedTestMethod,
+ details.TestCaseDisplayName,
+ details.UniqueID,
+ details.Explicit,
+ details.SkipExceptions,
+ details.SkipReason,
+ details.SkipType,
+ details.SkipUnless,
+ details.SkipWhen,
+ traits,
+ testMethodArguments,
+ sourceFilePath: details.SourceFilePath,
+ sourceLineNumber: details.SourceLineNumber,
+ timeout: details.Timeout);
+
+ return ValueTask.FromResult>([testCase]);
+ }
+
+ protected override ValueTask> CreateTestCasesForTheory(
+ ITestFrameworkDiscoveryOptions discoveryOptions,
+ IXunitTestMethod testMethod,
+ ITheoryAttribute theoryAttribute)
+ {
+ var details = TestIntrospectionHelper.GetTestCaseDetails(discoveryOptions, testMethod, theoryAttribute);
+
+ var testCase =
+ details.SkipReason is not null && details.SkipUnless is null && details.SkipWhen is null
+ ? new AvaloniaTestCase(
+ details.ResolvedTestMethod,
+ details.TestCaseDisplayName,
+ details.UniqueID,
+ details.Explicit,
+ details.SkipExceptions,
+ details.SkipReason,
+ details.SkipType,
+ details.SkipUnless,
+ details.SkipWhen,
+ testMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase),
+ sourceFilePath: details.SourceFilePath,
+ sourceLineNumber: details.SourceLineNumber,
+ timeout: details.Timeout
+ )
+ : (IXunitTestCase)new AvaloniaDelayEnumeratedTheoryTestCase(
+ details.ResolvedTestMethod,
+ details.TestCaseDisplayName,
+ details.UniqueID,
+ details.Explicit,
+ theoryAttribute.SkipTestWithoutData,
+ details.SkipExceptions,
+ details.SkipReason,
+ details.SkipType,
+ details.SkipUnless,
+ details.SkipWhen,
+ testMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase),
+ sourceFilePath: details.SourceFilePath,
+ sourceLineNumber: details.SourceLineNumber,
+ timeout: details.Timeout
+ );
+
+ return ValueTask.FromResult>([testCase]);
+ }
+}
diff --git a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryTestCase.cs b/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryTestCase.cs
deleted file mode 100644
index ea7e7abee4..0000000000
--- a/src/Headless/Avalonia.Headless.XUnit/AvaloniaTheoryTestCase.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Threading;
-using System.Threading.Tasks;
-using Xunit.Abstractions;
-using Xunit.Sdk;
-
-namespace Avalonia.Headless.XUnit;
-
-internal class AvaloniaTheoryTestCase : XunitTheoryTestCase
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
- public AvaloniaTheoryTestCase()
- {
- }
-
- public AvaloniaTheoryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod)
- : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod)
- {
- }
-
- public override Task RunAsync(IMessageSink diagnosticMessageSink, IMessageBus messageBus, object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
- {
- var session = HeadlessUnitTestSession.GetOrStartForAssembly(Method.ToRuntimeMethod().DeclaringType?.Assembly);
-
- return AvaloniaTestCaseRunner
- .RunTest(session, this, DisplayName, SkipReason, constructorArguments,
- TestMethodArguments, messageBus, aggregator, cancellationTokenSource);
- }
-}
diff --git a/src/Headless/Avalonia.Headless/Avalonia.Headless.csproj b/src/Headless/Avalonia.Headless/Avalonia.Headless.csproj
index bbd10677e9..edd5ed183b 100644
--- a/src/Headless/Avalonia.Headless/Avalonia.Headless.csproj
+++ b/src/Headless/Avalonia.Headless/Avalonia.Headless.csproj
@@ -6,6 +6,7 @@
+
diff --git a/src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
index e2c406998a..0a29b9a5b8 100644
--- a/src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
+++ b/src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
@@ -313,25 +313,25 @@ namespace Avalonia.Headless
_parent.Bounds = CalculateBounds();
}
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
+ public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked = true)
=> Track(point);
public void BeginFigure(Point startPoint, bool isFilled = true) => Track(startPoint);
- public void CubicBezierTo(Point point1, Point point2, Point point3)
+ public void CubicBezierTo(Point point1, Point point2, Point point3, bool isStroked = true)
{
Track(point1);
Track(point2);
Track(point3);
}
- public void QuadraticBezierTo(Point control, Point endPoint)
+ public void QuadraticBezierTo(Point control, Point endPoint, bool isStroked = true)
{
Track(control);
Track(endPoint);
}
- public void LineTo(Point point) => Track(point);
+ public void LineTo(Point point, bool isStroked = true) => Track(point);
public void EndFigure(bool isClosed)
{
@@ -559,12 +559,22 @@ namespace Avalonia.Headless
public void PushRenderOptions(RenderOptions renderOptions)
{
-
+
}
public void PopRenderOptions()
{
-
+
+ }
+
+ public void PushTextOptions(TextOptions textOptions)
+ {
+ // No-op in headless stub
+ }
+
+ public void PopTextOptions()
+ {
+ // No-op in headless stub
}
}
diff --git a/src/Headless/Avalonia.Headless/HeadlessUnitTestSession.cs b/src/Headless/Avalonia.Headless/HeadlessUnitTestSession.cs
index 65f648b98c..0e5a6b0c8b 100644
--- a/src/Headless/Avalonia.Headless/HeadlessUnitTestSession.cs
+++ b/src/Headless/Avalonia.Headless/HeadlessUnitTestSession.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Headless;
/// All UI tests are supposed to be executed from one of the methods to keep execution flow on the UI thread.
/// Disposing unit test session stops internal dispatcher loop.
///
-public sealed class HeadlessUnitTestSession : IDisposable
+public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
{
private static readonly Dictionary s_session = new();
@@ -184,6 +184,14 @@ public sealed class HeadlessUnitTestSession : IDisposable
_cancellationTokenSource.Dispose();
}
+ public async ValueTask DisposeAsync()
+ {
+ await _cancellationTokenSource.CancelAsync().ConfigureAwait(false);
+ _queue.CompleteAdding();
+ await _dispatchTask.ConfigureAwait(false);
+ _cancellationTokenSource.Dispose();
+ }
+
///
/// Creates instance of .
///
@@ -228,7 +236,9 @@ public sealed class HeadlessUnitTestSession : IDisposable
// If windowing subsystem wasn't initialized by user, force headless with default parameters.
if (appBuilder.WindowingSubsystemName != "Headless")
{
- appBuilder = appBuilder.UseHeadless(new AvaloniaHeadlessPlatformOptions());
+ appBuilder = appBuilder
+ .UseHeadless(new AvaloniaHeadlessPlatformOptions())
+ .UseHarfBuzz();
}
// ReSharper disable once AccessToModifiedClosure
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
index 88d708335e..a11dea95e4 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
@@ -142,7 +142,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
IXamlType? itemsCollectionType = null;
if (context.GetAvaloniaTypes().BindingBase.IsAssignableFrom(parentItemsValue.Type.GetClrType()))
{
- if (parentItemsValue.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension)
+ if (parentItemsValue.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBinding)
&& parentItemsValue is XamlMarkupExtensionNode ext && ext.Value is XamlAstConstructableObjectNode parentItemsBinding)
{
var parentItemsDataContext = context.ParentNodes().SkipWhile(n => n != parentObject).OfType().FirstOrDefault();
@@ -176,7 +176,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
private static AvaloniaXamlIlDataContextTypeMetadataNode ParseDataContext(AstTransformationContext context, XamlAstConstructableObjectNode on, XamlAstConstructableObjectNode obj)
{
var bindingType = context.GetAvaloniaTypes().BindingBase;
- if (!bindingType.IsAssignableFrom(obj.Type.GetClrType()) && !obj.Type.GetClrType().Equals(context.GetAvaloniaTypes().ReflectionBindingExtension))
+ if (!bindingType.IsAssignableFrom(obj.Type.GetClrType()) &&
+ !(obj.Type.GetClrType().Equals(context.GetAvaloniaTypes().ReflectionBindingExtension) ||
+ obj.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension)))
{
return new AvaloniaXamlIlDataContextTypeMetadataNode(on, obj.Type.GetClrType());
}
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
index 2b7a835fd8..8659eb1299 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
@@ -51,6 +51,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType ClrPropertyInfo { get; }
public IXamlType IPropertyAccessor { get; }
public IXamlType PropertyInfoAccessorFactory { get; }
+ public IXamlType CompiledBinding { get; }
public IXamlType CompiledBindingPathBuilder { get; }
public IXamlType CompiledBindingPath { get; }
public IXamlType CompiledBindingExtension { get; }
@@ -242,8 +243,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
ClrPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.ClrPropertyInfo");
IPropertyAccessor = cfg.TypeSystem.GetType("Avalonia.Data.Core.Plugins.IPropertyAccessor");
PropertyInfoAccessorFactory = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.PropertyInfoAccessorFactory");
- CompiledBindingPathBuilder = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.CompiledBindingPathBuilder");
- CompiledBindingPath = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.CompiledBindingPath");
+ CompiledBinding = cfg.TypeSystem.GetType("Avalonia.Data.CompiledBinding");
+ CompiledBindingPathBuilder = cfg.TypeSystem.GetType("Avalonia.Data.CompiledBindingPathBuilder");
+ CompiledBindingPath = cfg.TypeSystem.GetType("Avalonia.Data.CompiledBindingPath");
CompiledBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindingExtension");
ResolveByNameExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ResolveByNameExtension");
DataTemplate = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Templates.DataTemplate");
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
index 68dd595ea2..96af9a3a18 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
@@ -1013,11 +1013,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
var intType = context.Configuration.TypeSystem.GetType("System.Int32");
var types = context.GetAvaloniaTypes();
- // We're calling the CompiledBindingPathBuilder(int apiVersion) with an apiVersion
- // of 1 to indicate that we don't want TemplatedParent compatibility hacks enabled.
- codeGen
- .Ldc_I4(1)
- .Newobj(types.CompiledBindingPathBuilder.GetConstructor(new() { intType }));
+ codeGen.Newobj(types.CompiledBindingPathBuilder.GetConstructor());
foreach (var transform in _transformElements)
{
diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index 7a52f94a9f..e6186bbea6 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -20,7 +20,6 @@
-
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
index 0913903ff3..22606bdd93 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
@@ -7,15 +7,13 @@ using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Data.Core.ExpressionNodes;
using Avalonia.Data.Core.Parsers;
-using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
namespace Avalonia.Markup.Xaml.MarkupExtensions
{
- public sealed class CompiledBindingExtension : BindingBase
+ public sealed class CompiledBindingExtension : CompiledBinding
{
public CompiledBindingExtension()
{
- Path = new CompiledBindingPath();
}
public CompiledBindingExtension(CompiledBindingPath path)
@@ -23,9 +21,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
Path = path;
}
- public CompiledBindingExtension ProvideValue(IServiceProvider provider)
+ public CompiledBinding ProvideValue(IServiceProvider? provider)
{
- return new CompiledBindingExtension
+ return new CompiledBinding
{
Path = Path,
Delay = Delay,
@@ -38,184 +36,11 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
Priority = Priority,
StringFormat = StringFormat,
Source = Source,
- DefaultAnchor = new WeakReference(provider.GetDefaultAnchor()),
+ DefaultAnchor = new WeakReference(provider?.GetDefaultAnchor()),
UpdateSourceTrigger = UpdateSourceTrigger,
};
}
- ///
- /// Gets or sets the amount of time, in milliseconds, to wait before updating the binding
- /// source after the value on the target changes.
- ///
- ///
- /// There is no delay when the source is updated via
- /// or . Nor is there a delay when
- /// is active and a new source object is provided.
- ///
- public int Delay { get; set; }
-
- ///
- /// Gets or sets the to use.
- ///
- public IValueConverter? Converter { get; set; }
-
- ///
- /// Gets or sets the culture in which to evaluate the converter.
- ///
- /// The default value is null.
- ///
- /// If this property is not set then will be used.
- ///
- [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
- public CultureInfo? ConverterCulture { get; set; }
-
- ///
- /// Gets or sets a parameter to pass to .
- ///
- public object? ConverterParameter { get; set; }
-
public Type? DataType { get; set; }
-
- ///
- /// Gets or sets the value to use when the binding is unable to produce a value.
- ///
- public object? FallbackValue { get; set; } = AvaloniaProperty.UnsetValue;
-
- ///
- /// Gets or sets the binding mode.
- ///
- public BindingMode Mode { get; set; }
-
- [ConstructorArgument("path")]
- public CompiledBindingPath Path { get; set; }
-
- ///
- /// Gets or sets the binding priority.
- ///
- public BindingPriority Priority { get; set; }
-
- ///
- /// Gets or sets the source for the binding.
- ///
- public object? Source { get; set; } = AvaloniaProperty.UnsetValue;
-
- ///
- /// Gets or sets the string format.
- ///
- public string? StringFormat { get; set; }
-
- ///
- /// Gets or sets the value to use when the binding result is null.
- ///
- public object? TargetNullValue { get; set; } = AvaloniaProperty.UnsetValue;
-
- ///
- /// Gets or sets a value that determines the timing of binding source updates for
- /// and bindings.
- ///
- public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
-
- internal WeakReference? DefaultAnchor { get; set; }
-
- internal override BindingExpressionBase CreateInstance(
- AvaloniaObject target,
- AvaloniaProperty? targetProperty,
- object? anchor)
- {
- var enableDataValidation = targetProperty?.GetMetadata(target).EnableDataValidation ?? false;
- return InstanceCore(target, targetProperty, anchor, enableDataValidation);
- }
-
- ///
- /// Hack for TreeDataTemplate to create a binding expression for an item.
- ///
- /// The item.
- ///
- /// Ideally we'd do this in a more generic way but didn't have time to refactor
- /// ITreeDataTemplate in time for 11.0. We should revisit this in 12.0.
- ///
- // TODO12: Refactor
- internal BindingExpression CreateObservableForTreeDataTemplate(object source)
- {
- if (Source != AvaloniaProperty.UnsetValue)
- throw new NotSupportedException("Source bindings are not supported in this context.");
-
- var nodes = new List();
-
- Path.BuildExpression(nodes, out var isRooted);
-
- if (isRooted)
- throw new NotSupportedException("Rooted binding paths are not supported in this context.");
-
- return new BindingExpression(
- source,
- nodes,
- FallbackValue,
- delay: TimeSpan.FromMilliseconds(Delay),
- converter: Converter,
- converterParameter: ConverterParameter,
- targetNullValue: TargetNullValue);
- }
-
- private BindingExpression InstanceCore(
- AvaloniaObject target,
- AvaloniaProperty? targetProperty,
- object? anchor,
- bool enableDataValidation)
- {
- var nodes = new List();
-
- // Build the expression nodes from the binding path.
- Path.BuildExpression(nodes, out var isRooted);
-
- // If the binding isn't rooted (i.e. doesn't have a Source or start with $parent, $self,
- // #elementName etc.) then we need to add a data context source node.
- if (Source == AvaloniaProperty.UnsetValue && !isRooted)
- nodes.Insert(0, ExpressionNodeFactory.CreateDataContext(targetProperty));
-
- // If the first node is an ISourceNode then allow it to select the source; otherwise
- // use the binding source if specified, falling back to the target.
- var source = nodes.Count > 0 && nodes[0] is SourceNode sn
- ? sn.SelectSource(Source, target, anchor ?? DefaultAnchor?.Target)
- : Source != AvaloniaProperty.UnsetValue ? Source : target;
-
- var (mode, trigger) = ResolveDefaultsFromMetadata(target, targetProperty);
-
- return new BindingExpression(
- source,
- nodes,
- FallbackValue,
- delay: TimeSpan.FromMilliseconds(Delay),
- converter: Converter,
- converterCulture: ConverterCulture,
- converterParameter: ConverterParameter,
- enableDataValidation: enableDataValidation,
- mode: mode,
- priority: Priority,
- stringFormat: StringFormat,
- targetNullValue: TargetNullValue,
- targetProperty: targetProperty,
- targetTypeConverter: TargetTypeConverter.GetDefaultConverter(),
- updateSourceTrigger: trigger);
- }
-
- private (BindingMode, UpdateSourceTrigger) ResolveDefaultsFromMetadata(
- AvaloniaObject target,
- AvaloniaProperty? targetProperty)
- {
- var mode = Mode;
- var trigger = UpdateSourceTrigger == UpdateSourceTrigger.Default ?
- UpdateSourceTrigger.PropertyChanged : UpdateSourceTrigger;
-
- if (mode == BindingMode.Default)
- {
- if (targetProperty?.GetMetadata(target) is { } metadata)
- mode = metadata.DefaultBindingMode;
- else
- mode = BindingMode.OneWay;
- }
-
- return (mode, trigger);
- }
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs
index da4d7374d4..513b18c7a7 100644
--- a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Markup.Xaml
Type Resolve (string qualifiedTypeName);
}
-
+ // TODO12: Move to Avalonia.Base
[AttributeUsage(AttributeTargets.Property)]
public sealed class ConstructorArgumentAttribute : Attribute
{
diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
index 9c4c4f62fb..d5f541a014 100644
--- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
+++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
@@ -4,8 +4,6 @@
true
true
true
-
- $(WarningsAsErrors);CS0618
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.Effects.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.Effects.cs
index 7621e8436c..b661ad467d 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.Effects.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.Effects.cs
@@ -23,7 +23,7 @@ partial class DrawingContextImpl
public void PopEffect()
{
CheckLease();
- Canvas.Restore();
+ RestoreCanvas();
}
SKImageFilter? CreateEffect(IEffect effect)
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index e122c21242..42448ed631 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -27,6 +27,7 @@ namespace Avalonia.Skia
private readonly Stack<(SKMatrix matrix, PaintWrapper paint)> _maskStack = new();
private readonly Stack _opacityStack = new();
private readonly Stack _renderOptionsStack = new();
+ private readonly Stack _textOptionsStack = new();
private readonly Matrix? _postTransform;
private double _currentOpacity = 1.0f;
private readonly bool _disableSubpixelTextRendering;
@@ -223,6 +224,7 @@ namespace Avalonia.Skia
public SKSurface? Surface { get; }
public RenderOptions RenderOptions { get; set; }
+ public TextOptions TextOptions { get; set; }
private void CheckLease()
{
@@ -604,23 +606,32 @@ namespace Avalonia.Skia
{
var glyphRunImpl = (GlyphRunImpl)glyphRun;
- var textRenderOptions = RenderOptions;
+ // Determine effective TextOptions for text rendering. Start with current pushed TextOptions.
+ var effectiveTextOptions = TextOptions;
+ // If subpixel rendering is disabled globally, map subpixel modes to grayscale.
if (_disableSubpixelTextRendering)
{
- switch (textRenderOptions.TextRenderingMode)
+ var mode = effectiveTextOptions.TextRenderingMode;
+
+ if (mode == TextRenderingMode.SubpixelAntialias ||
+ (mode == TextRenderingMode.Unspecified && (RenderOptions.EdgeMode == EdgeMode.Antialias || RenderOptions.EdgeMode == EdgeMode.Unspecified)))
{
- case TextRenderingMode.Unspecified
- when textRenderOptions.EdgeMode == EdgeMode.Antialias || textRenderOptions.EdgeMode == EdgeMode.Unspecified:
- case TextRenderingMode.SubpixelAntialias:
- {
- textRenderOptions = textRenderOptions with { TextRenderingMode = TextRenderingMode.Antialias };
- break;
- }
+ effectiveTextOptions = effectiveTextOptions with { TextRenderingMode = TextRenderingMode.Antialias };
}
}
- var textBlob = glyphRunImpl.GetTextBlob(textRenderOptions);
+ var renderOptions = RenderOptions;
+
+ // If TextRenderingMode is unspecified in TextOptions, use the one from RenderOptions.
+#pragma warning disable CS0618
+ if (effectiveTextOptions.TextRenderingMode == TextRenderingMode.Unspecified && renderOptions.TextRenderingMode != TextRenderingMode.Unspecified)
+ {
+ effectiveTextOptions = effectiveTextOptions with { TextRenderingMode = renderOptions.TextRenderingMode };
+ }
+#pragma warning restore CS0618
+
+ var textBlob = glyphRunImpl.GetTextBlob(effectiveTextOptions, RenderOptions);
Canvas.DrawText(textBlob, (float)glyphRun.BaselineOrigin.X,
(float)glyphRun.BaselineOrigin.Y, paintWrapper.Paint);
@@ -755,11 +766,25 @@ namespace Avalonia.Skia
RenderOptions = RenderOptions.MergeWith(renderOptions);
}
+ public void PushTextOptions(TextOptions textOptions)
+ {
+ CheckLease();
+
+ _textOptionsStack.Push(TextOptions);
+
+ TextOptions = TextOptions.MergeWith(textOptions);
+ }
+
public void PopRenderOptions()
{
RenderOptions = _renderOptionsStack.Pop();
}
+ public void PopTextOptions()
+ {
+ TextOptions = _textOptionsStack.Pop();
+ }
+
///
public virtual void Dispose()
{
diff --git a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
index 30f6da1dc2..e7f772190d 100644
--- a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
+++ b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
@@ -15,13 +15,9 @@ namespace Avalonia.Skia
private readonly ushort[] _glyphIndices;
private readonly SKPoint[] _glyphPositions;
- // We use an array as opposed to a ConcurrentDictionary to prevent a large amount of lock object allocations.
- // This is possible because the SKFontEdging enum has consecutive integer elements 0, 1, 2, etc. and thus
- // can be mapped directly to array indices.
- //
- // Should Skia update the enum with more elements, then the size of this array should be updated appropriately.
- private const int FontEdgingsCount = (int)SKFontEdging.SubpixelAntialias + 1;
- private readonly SKTextBlob?[] _textBlobCache = new SKTextBlob?[FontEdgingsCount];
+ // A two level cache optimized for single-entry read. Uses TextOptions as a key.
+ private readonly TwoLevelCache _textBlobCache =
+ new TwoLevelCache(secondarySize: 3, evictionAction: b => b?.Dispose());
public GlyphRunImpl(GlyphTypeface glyphTypeface, double fontRenderingEmSize,
IReadOnlyList glyphInfos, Point baselineOrigin)
@@ -62,7 +58,14 @@ namespace Avalonia.Skia
// But the bounds depends on the edging: for now, always use SubpixelAntialias so we have consistent values.
// The resulting bounds may be shifted by 1px on some fonts:
// "F" text with Inter size 14 has a 0px left bound with SubpixelAntialias but 1px with Antialias.
- using var font = CreateFont(SKFontEdging.SubpixelAntialias);
+ var defaultTextOptions = default(TextOptions) with
+ {
+ TextRenderingMode = TextRenderingMode.SubpixelAntialias,
+ TextHintingMode = TextHintingMode.Strong,
+ BaselinePixelAlignment = BaselinePixelAlignment.Unaligned
+ };
+
+ using var font = CreateFont(defaultTextOptions);
var runBounds = new Rect();
var glyphBounds = ArrayPool.Shared.Rent(count);
@@ -92,26 +95,19 @@ namespace Avalonia.Skia
public Rect Bounds { get; }
- public SKTextBlob GetTextBlob(RenderOptions renderOptions)
+ public SKTextBlob GetTextBlob(TextOptions textOptions, RenderOptions renderOptions)
{
- var edging = SKFontEdging.SubpixelAntialias;
-
- switch (renderOptions.TextRenderingMode)
+ if (textOptions.TextRenderingMode == TextRenderingMode.Unspecified)
{
- case TextRenderingMode.Alias:
- edging = SKFontEdging.Alias;
- break;
- case TextRenderingMode.Antialias:
- edging = SKFontEdging.Antialias;
- break;
- case TextRenderingMode.Unspecified:
- edging = renderOptions.EdgeMode == EdgeMode.Aliased ? SKFontEdging.Alias : SKFontEdging.SubpixelAntialias;
- break;
+ textOptions = textOptions with
+ {
+ TextRenderingMode = renderOptions.EdgeMode == EdgeMode.Aliased ? TextRenderingMode.Alias : TextRenderingMode.SubpixelAntialias
+ };
}
- if (_textBlobCache[(int)edging] is null)
+ return _textBlobCache.GetOrAdd(textOptions, k =>
{
- using var font = CreateFont(edging);
+ using var font = CreateFont(textOptions);
var builder = SKTextBlobBuilderCache.Shared.Get();
@@ -121,37 +117,59 @@ namespace Avalonia.Skia
runBuffer.SetGlyphs(_glyphIndices);
var textBlob = builder.Build()!;
-
SKTextBlobBuilderCache.Shared.Return(builder);
-
- Interlocked.CompareExchange(ref _textBlobCache[(int)edging], textBlob, null);
- }
-
- return _textBlobCache[(int)edging]!;
+ return textBlob;
+ });
}
- private SKFont CreateFont(SKFontEdging edging)
+ private SKFont CreateFont(TextOptions textOptions)
{
+ // Determine edging from TextRenderingMode
+ var edging = textOptions.TextRenderingMode switch
+ {
+ TextRenderingMode.Alias => SKFontEdging.Alias,
+ TextRenderingMode.Antialias => SKFontEdging.Antialias,
+ TextRenderingMode.SubpixelAntialias => SKFontEdging.SubpixelAntialias,
+ _ => SKFontEdging.SubpixelAntialias
+ };
+
+ // Determine hinting
+ var hinting = textOptions.TextHintingMode switch
+ {
+ TextHintingMode.None => SKFontHinting.None,
+ TextHintingMode.Light => SKFontHinting.Slight,
+ TextHintingMode.Strong => SKFontHinting.Full,
+ _ => SKFontHinting.Full,
+ };
+
+ // Force auto-hinting for "Slight" mode (prefer autohinter over bytecode hints), otherwise default.
+ var forceAutoHinting = textOptions.TextHintingMode == TextHintingMode.Light;
+
+ // Subpixel rendering enabled when edging is not alias.
+ var subpixel = edging != SKFontEdging.Alias;
+
+ // Baseline snap defaults to true unless explicitly disabled.
+ var baselineSnap = textOptions.BaselinePixelAlignment != BaselinePixelAlignment.Unaligned;
+
var font = _glyphTypefaceImpl.CreateSKFont((float)FontRenderingEmSize);
- font.Hinting = SKFontHinting.Full;
- font.Subpixel = edging != SKFontEdging.Alias;
+ font.ForceAutoHinting = forceAutoHinting;
+ font.Hinting = hinting;
+ font.Subpixel = subpixel;
font.Edging = edging;
+ font.BaselineSnap = baselineSnap;
return font;
}
public void Dispose()
{
- foreach (var textBlob in _textBlobCache)
- {
- textBlob?.Dispose();
- }
+ _textBlobCache.ClearAndDispose();
}
public IReadOnlyList GetIntersections(float lowerLimit, float upperLimit)
{
- var textBlob = GetTextBlob(default);
+ var textBlob = GetTextBlob(default, default);
return textBlob.GetIntercepts(lowerLimit, upperLimit);
}
diff --git a/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs b/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs
index 940a1c7247..f56cd274bf 100644
--- a/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs
+++ b/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs
@@ -1,5 +1,3 @@
-using System.Diagnostics.CodeAnalysis;
-using System.Drawing;
using Avalonia.Media;
using Avalonia.Platform;
using SkiaSharp;
@@ -78,7 +76,7 @@ namespace Avalonia.Skia
///
/// A Skia implementation of a .
///
- private class StreamContext : IStreamGeometryContextImpl, IGeometryContext2
+ private class StreamContext : IStreamGeometryContextImpl
{
private readonly StreamGeometryImpl _geometryImpl;
private SKPath Stroke => _geometryImpl._strokePath;
@@ -122,33 +120,7 @@ namespace Avalonia.Skia
}
///
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
- {
- var arc = isLargeArc ? SKPathArcSize.Large : SKPathArcSize.Small;
- var sweep = sweepDirection == SweepDirection.Clockwise
- ? SKPathDirection.Clockwise
- : SKPathDirection.CounterClockwise;
- Stroke.ArcTo(
- (float)size.Width,
- (float)size.Height,
- (float)rotationAngle,
- arc,
- sweep,
- (float)point.X,
- (float)point.Y);
- if (Duplicate)
- Fill.ArcTo(
- (float)size.Width,
- (float)size.Height,
- (float)rotationAngle,
- arc,
- sweep,
- (float)point.X,
- (float)point.Y);
- }
-
- ///
- public void BeginFigure(Point startPoint, bool isFilled)
+ public void BeginFigure(Point startPoint, bool isFilled = true)
{
if (!isFilled)
EnsureSeparateFillPath();
@@ -161,30 +133,6 @@ namespace Avalonia.Skia
Fill.MoveTo((float)startPoint.X, (float)startPoint.Y);
}
- ///
- public void CubicBezierTo(Point point1, Point point2, Point point3)
- {
- Stroke.CubicTo((float)point1.X, (float)point1.Y, (float)point2.X, (float)point2.Y, (float)point3.X, (float)point3.Y);
- if (Duplicate)
- Fill.CubicTo((float)point1.X, (float)point1.Y, (float)point2.X, (float)point2.Y, (float)point3.X, (float)point3.Y);
- }
-
- ///
- public void QuadraticBezierTo(Point point1, Point point2)
- {
- Stroke.QuadTo((float)point1.X, (float)point1.Y, (float)point2.X, (float)point2.Y);
- if (Duplicate)
- Fill.QuadTo((float)point1.X, (float)point1.Y, (float)point2.X, (float)point2.Y);
- }
-
- ///
- public void LineTo(Point point)
- {
- Stroke.LineTo((float)point.X, (float)point.Y);
- if (Duplicate)
- Fill.LineTo((float)point.X, (float)point.Y);
- }
-
///
public void EndFigure(bool isClosed)
{
@@ -209,7 +157,7 @@ namespace Avalonia.Skia
}
///
- public void LineTo(Point point, bool isStroked)
+ public void LineTo(Point point, bool isStroked = true)
{
if (isStroked)
{
@@ -225,7 +173,7 @@ namespace Avalonia.Skia
}
///
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked)
+ public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked = true)
{
var arc = isLargeArc ? SKPathArcSize.Large : SKPathArcSize.Small;
var sweep = sweepDirection == SweepDirection.Clockwise
@@ -260,7 +208,7 @@ namespace Avalonia.Skia
}
///
- public void CubicBezierTo(Point point1, Point point2, Point point3, bool isStroked)
+ public void CubicBezierTo(Point point1, Point point2, Point point3, bool isStroked = true)
{
if (isStroked)
{
@@ -276,7 +224,7 @@ namespace Avalonia.Skia
}
///
- public void QuadraticBezierTo(Point point1, Point point2, bool isStroked)
+ public void QuadraticBezierTo(Point point1, Point point2, bool isStroked = true)
{
if (isStroked)
{
diff --git a/src/Skia/Avalonia.Skia/TwoLevelCache.cs b/src/Skia/Avalonia.Skia/TwoLevelCache.cs
new file mode 100644
index 0000000000..cfc14fae4c
--- /dev/null
+++ b/src/Skia/Avalonia.Skia/TwoLevelCache.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+
+namespace Avalonia.Skia
+{
+ ///
+ /// Provides a lightweight two-level cache for storing key-value pairs, supporting fast retrieval and optional
+ /// eviction handling.
+ ///
+ /// The cache maintains a primary entry for the most recently added item and a secondary array
+ /// for additional items, with a configurable capacity. When the cache exceeds its capacity, evicted values can be
+ /// processed using an optional eviction action. This class is intended for internal use and is not
+ /// thread-safe.
+ /// The type of keys used to identify cached values. Must be non-nullable.
+ /// The type of values to be stored in the cache. Must be a reference type.
+ internal class TwoLevelCache
+ where TKey : notnull
+ where TValue : class
+ {
+ private readonly int _secondarySize;
+ private TKey? _primaryKey;
+ private TValue? _primaryValue;
+ private KeyValuePair[]? _secondary;
+ private int _secondaryCount;
+ private readonly Action? _evictionAction;
+ private readonly IEqualityComparer _comparer;
+
+ public TwoLevelCache(int secondarySize = 3, Action? evictionAction = null, IEqualityComparer? comparer = null)
+ {
+ if (secondarySize < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(secondarySize));
+ }
+
+ _secondarySize = secondarySize;
+ _evictionAction = evictionAction;
+ _comparer = comparer ?? EqualityComparer.Default;
+ }
+
+ public bool TryGet(TKey key, out TValue? value)
+ {
+ if (_primaryValue != null && _comparer.Equals(_primaryKey!, key))
+ {
+ value = _primaryValue;
+ return true;
+ }
+
+ var sec = _secondary;
+ if (sec != null)
+ {
+ for (int i = 0; i < _secondaryCount; i++)
+ {
+ if (_comparer.Equals(sec[i].Key, key))
+ {
+ value = sec[i].Value;
+ return true;
+ }
+ }
+ }
+
+ value = null;
+ return false;
+ }
+
+ public TValue GetOrAdd(TKey key, Func factory)
+ {
+ // Check if key already exists
+ if (TryGet(key, out var existing) && existing != null)
+ {
+ return existing;
+ }
+
+ // Key doesn't exist, create new value
+ var value = factory(key);
+
+ // Primary is empty - store in primary
+ if (_primaryValue == null)
+ {
+ _primaryKey = key;
+ _primaryValue = value;
+ return value;
+ }
+
+ // No secondary cache configured - replace primary
+ if (_secondarySize == 0)
+ {
+ _evictionAction?.Invoke(_primaryValue);
+ _primaryKey = key;
+ _primaryValue = value;
+ return value;
+ }
+
+ // Secondary not yet initialized - create it
+ if (_secondary == null)
+ {
+ _secondary = new KeyValuePair[_secondarySize];
+ _secondaryCount = 0;
+ }
+
+ // Shift existing entries right and insert new one at front
+ // This maintains insertion order and evicts the oldest (last) entry when full
+ TValue? evicted = default;
+ bool shouldEvict = _secondaryCount == _secondarySize;
+
+ if (shouldEvict)
+ {
+ // Cache is full, last entry will be evicted
+ evicted = _secondary[_secondarySize - 1].Value;
+ }
+
+ // Shift existing entries to make room at index 0
+ int shiftCount = shouldEvict ? _secondarySize - 1 : _secondaryCount;
+ for (int i = shiftCount; i > 0; i--)
+ {
+ _secondary[i] = _secondary[i - 1];
+ }
+
+ // Insert new entry at front
+ _secondary[0] = new KeyValuePair(key, value);
+
+ // Update count (capped at size)
+ if (_secondaryCount < _secondarySize)
+ {
+ _secondaryCount++;
+ }
+
+ // Invoke eviction action if we evicted an entry
+ if (shouldEvict)
+ {
+ _evictionAction?.Invoke(evicted);
+ }
+
+ return value;
+ }
+
+ public void ClearAndDispose()
+ {
+ if (_primaryValue != null)
+ {
+ _evictionAction?.Invoke(_primaryValue);
+ _primaryValue = null;
+ _primaryKey = default;
+ }
+
+ if (_secondary != null)
+ {
+ for (int i = 0; i < _secondaryCount; i++)
+ {
+ _evictionAction?.Invoke(_secondary[i].Value);
+ }
+
+ _secondary = null;
+ _secondaryCount = 0;
+ }
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32.Automation/AutomationNode.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.cs
index 45216a4c09..8562807452 100644
--- a/src/Windows/Avalonia.Win32.Automation/AutomationNode.cs
+++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.cs
@@ -54,10 +54,8 @@ namespace Avalonia.Win32.Automation
{ SelectionPatternIdentifiers.IsSelectionRequiredProperty, UiaPropertyId.SelectionIsSelectionRequired },
{ SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection },
{ SelectionItemPatternIdentifiers.IsSelectedProperty, UiaPropertyId.SelectionItemIsSelected },
- {
- SelectionItemPatternIdentifiers.SelectionContainerProperty,
- UiaPropertyId.SelectionItemSelectionContainer
- }
+ { SelectionItemPatternIdentifiers.SelectionContainerProperty, UiaPropertyId.SelectionItemSelectionContainer },
+ { TogglePatternIdentifiers.ToggleStateProperty, UiaPropertyId.ToggleToggleState },
};
private static ConditionalWeakTable s_nodes = new();
@@ -143,6 +141,7 @@ namespace Avalonia.Win32.Automation
UiaPropertyId.LandmarkType => InvokeSync(() => ToUiaLandmarkType(Peer.GetLandmarkType())),
UiaPropertyId.LocalizedLandmarkType => InvokeSync(() => ToUiaLocalizedLandmarkType(Peer.GetLandmarkType())),
UiaPropertyId.HeadingLevel => InvokeSync(() => ToUiaHeadingLevel(Peer.GetHeadingLevel())),
+ UiaPropertyId.LiveSetting => InvokeSync(() => ToUiaLiveSetting(Peer.GetLiveSetting())),
UiaPropertyId.ProcessId => s_pid,
UiaPropertyId.RuntimeId => _runtimeId,
_ => null,
@@ -275,6 +274,13 @@ namespace Avalonia.Win32.Automation
(int)UiaEventId.AutomationFocusChanged);
}
+ protected void RaiseLiveRegionChanged()
+ {
+ UiaCoreProviderApi.UiaRaiseAutomationEvent(
+ this,
+ (int)UiaEventId.LiveRegionChanged);
+ }
+
private RootAutomationNode? GetRoot()
{
Dispatcher.UIThread.VerifyAccess();
@@ -296,6 +302,11 @@ namespace Avalonia.Win32.Automation
e.OldValue as IConvertible,
e.NewValue as IConvertible);
}
+
+ if (id == UiaPropertyId.Name && Peer.GetLiveSetting() != AutomationLiveSetting.Off)
+ {
+ RaiseLiveRegionChanged();
+ }
}
private void OnEmbeddedRootFocusChanged(object? sender, EventArgs e)
@@ -359,6 +370,7 @@ namespace Avalonia.Win32.Automation
AutomationControlType.Table => UiaControlTypeId.Table,
AutomationControlType.TitleBar => UiaControlTypeId.TitleBar,
AutomationControlType.Separator => UiaControlTypeId.Separator,
+ AutomationControlType.Expander => UiaControlTypeId.Group,
_ => UiaControlTypeId.Custom,
};
}
@@ -408,6 +420,8 @@ namespace Avalonia.Win32.Automation
};
}
+ private static UiaLiveSetting ToUiaLiveSetting(AutomationLiveSetting liveSetting) => (UiaLiveSetting)liveSetting;
+
private static int GetProcessId()
{
#if NET6_0_OR_GREATER
diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs
index bbbb2a29e2..bf70aa1f40 100644
--- a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs
+++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs
@@ -300,6 +300,13 @@ internal enum UiaHeadingLevel
Level9
};
+internal enum UiaLiveSetting
+{
+ Off = 0,
+ Polite,
+ Assertive,
+};
+
#if NET8_0_OR_GREATER
[GeneratedComInterface]
#else
diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
index c734c474a6..109cba5850 100644
--- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
+++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
@@ -3,8 +3,6 @@
$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks)
true
true
-
- true
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
index e7007c3448..c1e77aab76 100644
--- a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
@@ -1,13 +1,20 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Avalonia.Logging;
using Avalonia.OpenGL.Egl;
using Avalonia.Rendering;
-using static Avalonia.Win32.Interop.UnmanagedMethods;
-using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods;
+
using MicroCom.Runtime;
+using Windows.Win32;
+using Windows.Win32.Graphics.Gdi;
+
+using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods;
+using static Avalonia.Win32.Interop.UnmanagedMethods;
+
namespace Avalonia.Win32.DirectX
{
internal unsafe class DxgiConnection : IRenderTimer, IWindowsSurfaceFactory
@@ -111,6 +118,8 @@ namespace Avalonia.Win32.DirectX
ushort adapterIndex = 0;
+ Dictionary monitorFrequencies = GetAllMonitorFrequencies();
+
// this looks odd, but that's just how one enumerates adapters in DXGI
while (fact.EnumAdapters(adapterIndex, &adapterPointer) == 0)
{
@@ -122,8 +131,12 @@ namespace Avalonia.Win32.DirectX
using var output = MicroComRuntime.CreateProxyFor(outputPointer, true);
DXGI_OUTPUT_DESC outputDesc = output.Desc;
- var screen = Win32Platform.Instance.Screen.ScreenFromHMonitor((IntPtr)outputDesc.Monitor.Value);
- var frequency = screen?.Frequency ?? highestRefreshRate;
+ var hMonitor = new HMONITOR(outputDesc.Monitor.Value);
+
+ var frequency =
+ monitorFrequencies.TryGetValue(hMonitor, out uint frequencyValue) ?
+ frequencyValue :
+ highestRefreshRate;
if (highestRefreshRate < frequency)
{
@@ -145,6 +158,33 @@ namespace Avalonia.Win32.DirectX
}
+ private unsafe Dictionary GetAllMonitorFrequencies()
+ {
+ var monitorHandlers = ScreenImpl.GetAllDisplayMonitorHandlers();
+ var dictionary = new Dictionary(monitorHandlers.Count);
+
+ foreach (var monitorHandler in monitorHandlers)
+ {
+ var info = MONITORINFOEX.Create();
+ var hMonitor = new HMONITOR(monitorHandler);
+ PInvoke.GetMonitorInfo(hMonitor, (MONITORINFO*)&info);
+
+ var deviceMode = new DEVMODEW
+ {
+ dmFields = DEVMODE_FIELD_FLAGS.DM_DISPLAYORIENTATION | DEVMODE_FIELD_FLAGS.DM_DISPLAYFREQUENCY,
+ dmSize = (ushort)Marshal.SizeOf()
+ };
+ PInvoke.EnumDisplaySettings(info.szDevice.ToString(), ENUM_DISPLAY_SETTINGS_MODE.ENUM_CURRENT_SETTINGS,
+ ref deviceMode);
+
+ var frequency = deviceMode.dmDisplayFrequency;
+
+ dictionary[hMonitor] = frequency;
+ }
+
+ return dictionary;
+ }
+
// Used the windows composition as a blueprint for this startup/creation
private static bool TryCreateAndRegisterCore()
{
@@ -168,6 +208,7 @@ namespace Avalonia.Win32.DirectX
});
thread.IsBackground = true;
thread.SetApartmentState(System.Threading.ApartmentState.STA);
+ thread.Name = "DxgiRenderTimerLoop";
thread.Start();
// block until
return tcs.Task.Result;
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
index c7306ce86e..6470aa48b8 100644
--- a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
@@ -23,7 +23,8 @@ namespace Avalonia.Win32.DirectX
private IUnknown? _renderTexture;
private RECT _clientRect;
-
+ private EglSurface? _surface;
+
public DxgiRenderTarget(EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo window, EglContext context, DxgiConnection connection) : base(context)
{
_window = window;
@@ -83,7 +84,6 @@ namespace Avalonia.Win32.DirectX
}
var contextLock = Context.EnsureCurrent();
- EglSurface? surface = null;
IDisposable? transaction = null;
var success = false;
try
@@ -96,6 +96,9 @@ namespace Avalonia.Win32.DirectX
if (_renderTexture is not null)
{
+ _surface?.Dispose();
+ _surface = null;
+
_renderTexture.Dispose();
_renderTexture = null;
}
@@ -114,19 +117,24 @@ namespace Avalonia.Win32.DirectX
var texture = _renderTexture;
if (texture is null)
{
+ _surface?.Dispose();
+ _surface = null;
+
Guid textureGuid = ID3D11Texture2DGuid;
texture = MicroComRuntime.CreateProxyFor(_swapChain.GetBuffer(0, &textureGuid), true);
}
_renderTexture = texture;
- // I also have to get the pointer to this texture directly
- surface = ((AngleWin32EglDisplay)Context.Display).WrapDirect3D11Texture(MicroComRuntime.GetNativeIntPtr(_renderTexture),
- 0, 0, size.Width, size.Height);
+ if (_surface is null)
+ {
+ // I also have to get the pointer to this texture directly
+ _surface = ((AngleWin32EglDisplay)Context.Display).WrapDirect3D11Texture(MicroComRuntime.GetNativeIntPtr(_renderTexture),
+ 0, 0, size.Width, size.Height);
+ }
- var res = base.BeginDraw(surface, _window.Size, _window.Scaling, () =>
+ var res = base.BeginDraw(_surface, _window.Size, _window.Scaling, () =>
{
_swapChain.Present((ushort)0U, (ushort)0U);
- surface.Dispose();
transaction?.Dispose();
contextLock?.Dispose();
}, true);
@@ -137,7 +145,8 @@ namespace Avalonia.Win32.DirectX
{
if (!success)
{
- surface?.Dispose();
+ _surface?.Dispose();
+ _surface = null;
if (_renderTexture is not null)
{
_renderTexture.Dispose();
@@ -155,6 +164,7 @@ namespace Avalonia.Win32.DirectX
_dxgiDevice?.Dispose();
_dxgiFactory?.Dispose();
_swapChain?.Dispose();
+ _surface?.Dispose();
_renderTexture?.Dispose();
}
diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs
index 0f73d39249..b4bff3da35 100644
--- a/src/Windows/Avalonia.Win32/ScreenImpl.cs
+++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs
@@ -15,6 +15,11 @@ internal unsafe class ScreenImpl : ScreensBase
protected override int GetScreenCount() => GetSystemMetrics(SystemMetric.SM_CMONITORS);
protected override IReadOnlyList GetAllScreenKeys()
+ {
+ return GetAllDisplayMonitorHandlers();
+ }
+
+ public static List GetAllDisplayMonitorHandlers()
{
var screens = new List();
var gcHandle = GCHandle.Alloc(screens);
diff --git a/src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs b/src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs
index 2618dad857..70e35e3973 100644
--- a/src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs
+++ b/src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.Versioning;
using Foundation;
using Avalonia.Controls.ApplicationLifetimes;
using UIKit;
@@ -27,6 +28,7 @@ namespace Avalonia.iOS
add { _onActivated += value; }
remove { _onActivated -= value; }
}
+
event EventHandler IAvaloniaAppDelegate.Deactivated
{
add { _onDeactivated += value; }
@@ -39,6 +41,17 @@ namespace Avalonia.iOS
[Export("window")]
public UIWindow? Window { get; set; }
+ [Export("application:configurationForConnectingSceneSession:options:")]
+ [SupportedOSPlatform("ios13.0")]
+ [SupportedOSPlatform("tvos13.0")]
+ [SupportedOSPlatform("maccatalyst")]
+ public UISceneConfiguration GetConfiguration(UIApplication application, UISceneSession connectingSceneSession, UISceneConnectionOptions options)
+ {
+ var config = new UISceneConfiguration(null, connectingSceneSession.Role);
+ config.DelegateType = typeof(AvaloniaSceneDelegate);
+ return config;
+ }
+
[Export("application:didFinishLaunchingWithOptions:")]
public bool FinishedLaunching(UIApplication application, NSDictionary? launchOptions)
{
@@ -46,28 +59,27 @@ namespace Avalonia.iOS
builder = CustomizeAppBuilder(builder);
var lifetime = new SingleViewLifetime();
-
- builder.AfterApplicationSetup(_ =>
- {
- Window = new UIWindow();
-
- var view = new AvaloniaView();
- lifetime.View = view;
- var controller = new DefaultAvaloniaViewController
- {
- View = view
- };
- Window.RootViewController = controller;
- view.InitWithController(controller);
- });
-
+ builder.AfterApplicationSetup(_ => CreateAndInitWindow(lifetime));
builder.SetupWithLifetime(lifetime);
- Window!.MakeKeyAndVisible();
+ Window?.MakeKeyAndVisible();
return true;
}
+ private void CreateAndInitWindow(SingleViewLifetime lifetime)
+ {
+ if (OperatingSystem.IsIOSVersionAtLeast(13) ||
+ OperatingSystem.IsTvOSVersionAtLeast(13) ||
+ OperatingSystem.IsMacCatalyst())
+ {
+ return;
+ }
+
+ Window = new UIWindow();
+ AvaloniaSceneDelegate.InitWindow(Window, lifetime);
+ }
+
[Export("application:openURL:options:")]
public bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
diff --git a/src/iOS/Avalonia.iOS/AvaloniaSceneDelegate.cs b/src/iOS/Avalonia.iOS/AvaloniaSceneDelegate.cs
new file mode 100644
index 0000000000..e4bbb4843e
--- /dev/null
+++ b/src/iOS/Avalonia.iOS/AvaloniaSceneDelegate.cs
@@ -0,0 +1,36 @@
+using Foundation;
+using UIKit;
+
+namespace Avalonia.iOS;
+
+internal sealed class AvaloniaSceneDelegate : UIResponder, IUIWindowSceneDelegate
+{
+ [Export("window")]
+ public UIWindow? Window { get; set; }
+
+ [Export("scene:willConnectToSession:options:")]
+ public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
+ {
+ if (session.Configuration.Name is not null ||
+ scene is not UIWindowScene windowScene ||
+ Application.Current?.ApplicationLifetime is not SingleViewLifetime lifetime)
+ {
+ return;
+ }
+
+ Window = new UIWindow(windowScene);
+ InitWindow(Window, lifetime);
+
+ Window.MakeKeyAndVisible();
+ }
+
+ internal static void InitWindow(UIWindow window, SingleViewLifetime lifetime)
+ {
+ var view = new AvaloniaView();
+ lifetime.View = view;
+
+ var controller = new DefaultAvaloniaViewController { View = view };
+ window.RootViewController = controller;
+ view.InitWithController(controller);
+ }
+}
diff --git a/src/iOS/Avalonia.iOS/SingleViewLifetime.cs b/src/iOS/Avalonia.iOS/SingleViewLifetime.cs
index 7c56904fdc..913148197d 100644
--- a/src/iOS/Avalonia.iOS/SingleViewLifetime.cs
+++ b/src/iOS/Avalonia.iOS/SingleViewLifetime.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Avalonia.Controls;
+using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.iOS;
@@ -10,9 +8,9 @@ internal class SingleViewLifetime : ISingleViewApplicationLifetime, ISingleTopLe
private Control? _mainView;
private AvaloniaView? _view;
- public AvaloniaView View
+ public AvaloniaView? View
{
- [return: MaybeNull] get => _view!;
+ get => _view;
internal set
{
if (_view != null)
@@ -21,7 +19,7 @@ internal class SingleViewLifetime : ISingleViewApplicationLifetime, ISingleTopLe
_view.Dispose();
}
_view = value;
- _view.Content = _mainView;
+ _view?.Content = _mainView;
}
}
@@ -33,10 +31,7 @@ internal class SingleViewLifetime : ISingleViewApplicationLifetime, ISingleTopLe
if (_mainView != value)
{
_mainView = value;
- if (_view != null)
- {
- _view.Content = _mainView;
- }
+ _view?.Content = _mainView;
}
}
}
diff --git a/tests/Avalonia.Base.UnitTests/Data/Core/CompiledBindingPathFromExpressionBuilder.cs b/tests/Avalonia.Base.UnitTests/Data/Core/CompiledBindingPathFromExpressionBuilder.cs
index 0662fd94b0..d3623fde80 100644
--- a/tests/Avalonia.Base.UnitTests/Data/Core/CompiledBindingPathFromExpressionBuilder.cs
+++ b/tests/Avalonia.Base.UnitTests/Data/Core/CompiledBindingPathFromExpressionBuilder.cs
@@ -1,10 +1,9 @@
using System;
-using System.Collections.Generic;
-using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
+using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs
index 02c67c5896..a12e5015fd 100644
--- a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs
+++ b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs
@@ -54,9 +54,9 @@ public abstract class PointerTestsBase : ScopedTestBase
impl.Setup(r => r.PointToScreen(It.IsAny())).Returns(p => new PixelPoint((int)p.X, (int)p.Y));
impl.Setup(r => r.PointToClient(It.IsAny())).Returns(p => new Point(p.X, p.Y));
- var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
+ var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
var screens = new Mock();
- screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1);
impl.Setup(x => x.TryGetFeature(It.Is(t => t == typeof(IScreenImpl)))).Returns(screens.Object);
return impl;
diff --git a/tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs
deleted file mode 100644
index b7d09a40d7..0000000000
--- a/tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using Avalonia.Utilities;
-using Xunit;
-
-#pragma warning disable CS0618 // Type or member is obsolete
-
-namespace Avalonia.Base.UnitTests.Utilities
-{
- public class StringTokenizerTests
- {
- [Fact]
- public void ReadInt32_Reads_Values()
- {
- var target = new StringTokenizer("123,456");
-
- Assert.Equal(123, target.ReadInt32());
- Assert.Equal(456, target.ReadInt32());
- Assert.Throws(() => target.ReadInt32());
- }
-
- [Fact]
- public void ReadDouble_Reads_Values()
- {
- var target = new StringTokenizer("12.3,45.6");
-
- Assert.Equal(12.3, target.ReadDouble());
- Assert.Equal(45.6, target.ReadDouble());
- Assert.Throws(() => target.ReadDouble());
- }
-
- [Fact]
- public void TryReadInt32_Reads_Values()
- {
- var target = new StringTokenizer("123,456");
-
- Assert.True(target.TryReadInt32(out var value));
- Assert.Equal(123, value);
- Assert.True(target.TryReadInt32(out value));
- Assert.Equal(456, value);
- Assert.False(target.TryReadInt32(out value));
- }
-
- [Fact]
- public void TryReadInt32_Doesnt_Throw()
- {
- var target = new StringTokenizer("abc");
-
- Assert.False(target.TryReadInt32(out var value));
- }
-
- [Fact]
- public void TryReadDouble_Reads_Values()
- {
- var target = new StringTokenizer("12.3,45.6");
-
- Assert.True(target.TryReadDouble(out var value));
- Assert.Equal(12.3, value);
- Assert.True(target.TryReadDouble(out value));
- Assert.Equal(45.6, value);
- Assert.False(target.TryReadDouble(out value));
- }
-
- [Fact]
- public void TryReadDouble_Doesnt_Throw()
- {
- var target = new StringTokenizer("abc");
-
- Assert.False(target.TryReadDouble(out var value));
- }
-
- [Fact]
- public void ReadSpan_And_ReadString_Reads_Same()
- {
- var target1 = new StringTokenizer("abc,def");
- var target2 = new StringTokenizer("abc,def");
-
- Assert.Equal(target1.ReadString(), target2.ReadSpan().ToString());
- Assert.True(target1.ReadSpan().SequenceEqual(target2.ReadString()));
- }
- }
-}
diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
index dcfd7d8ab2..51ed2296a3 100644
--- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
@@ -666,7 +666,7 @@ namespace Avalonia.Controls.UnitTests
var screen = new PixelRect(new PixelPoint(), new PixelSize(100, 100));
var screenImpl = new Mock();
screenImpl.Setup(x => x.ScreenCount).Returns(1);
- screenImpl.Setup(X => X.AllScreens).Returns( new[] { new Screen(1, screen, screen, true) });
+ screenImpl.Setup(X => X.AllScreens).Returns( new[] { new MockScreen(1, screen, screen, true) });
var windowImpl = MockWindowingPlatform.CreateWindowMock();
_popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object);
diff --git a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs
index bae1f91319..aa213d996c 100644
--- a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs
@@ -300,9 +300,9 @@ namespace Avalonia.Controls.UnitTests
windowImpl.Setup(x => x.DesktopScaling).Returns(1);
windowImpl.Setup(x => x.RenderScaling).Returns(1);
- var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
+ var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
var screens = new Mock();
- screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1);
windowImpl.Setup(x => x.TryGetFeature(It.Is(t => t == typeof(IScreenImpl)))).Returns(screens.Object);
var services = TestServices.StyledWindow.With(
diff --git a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
index 35bf427bc1..c143f8db12 100644
--- a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
@@ -848,7 +848,7 @@ namespace Avalonia.Controls.UnitTests
var screen = new PixelRect(new PixelPoint(), new PixelSize(100, 100));
var screenImpl = new Mock();
screenImpl.Setup(x => x.ScreenCount).Returns(1);
- screenImpl.Setup(X => X.AllScreens).Returns(new[] { new Screen(1, screen, screen, true) });
+ screenImpl.Setup(X => X.AllScreens).Returns(new[] { new MockScreen(1, screen, screen, true) });
var windowImpl = MockWindowingPlatform.CreateWindowMock();
_popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object);
diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/ShapeTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/ShapeTests.cs
index ac5dded8fc..b7b5604135 100644
--- a/tests/Avalonia.Controls.UnitTests/Shapes/ShapeTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Shapes/ShapeTests.cs
@@ -180,6 +180,10 @@ public class ShapeTests : ScopedTestBase
protected override void PushRenderOptionsCore(RenderOptions renderOptions)
{
+ }
+
+ protected override void PushTextOptionsCore(TextOptions textOptions)
+ {
}
protected override void PushTransformCore(Matrix matrix)
@@ -210,6 +214,10 @@ public class ShapeTests : ScopedTestBase
{
}
+ protected override void PopTextOptionsCore()
+ {
+ }
+
protected override void DisposeCore()
{
}
diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
index 2ec0b7f80d..24b17c46f7 100644
--- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
@@ -518,11 +518,11 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Window_Should_Not_Be_Centered_When_WindowStartupLocation_Is_CenterScreen_And_Window_Is_Hidden_And_Shown()
{
- var screen1 = new Mock(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true);
+ var screen1 = new MockScreen(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true);
var screens = new Mock();
- screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object });
- screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1 });
+ screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1);
var windowImpl = MockWindowingPlatform.CreateWindowMock();
@@ -553,12 +553,12 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen()
{
- var screen1 = new Mock(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true);
- var screen2 = new Mock(1.0, new PixelRect(new PixelSize(1366, 768)), new PixelRect(new PixelSize(1366, 728)), false);
+ var screen1 = new MockScreen(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true);
+ var screen2 = new MockScreen(1.0, new PixelRect(new PixelSize(1366, 768)), new PixelRect(new PixelSize(1366, 728)), false);
var screens = new Mock();
- screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object, screen2.Object });
- screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1, screen2 });
+ screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1);
var windowImpl = MockWindowingPlatform.CreateWindowMock();
@@ -576,8 +576,8 @@ namespace Avalonia.Controls.UnitTests
window.Show();
var expectedPosition = new PixelPoint(
- (int)(screen1.Object.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2),
- (int)(screen1.Object.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2));
+ (int)(screen1.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2),
+ (int)(screen1.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2));
Assert.Equal(window.Position, expectedPosition);
}
@@ -586,10 +586,10 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Window_Should_Be_Sized_To_MinSize_If_InitialSize_Less_Than_MinSize()
{
- var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
+ var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
var screens = new Mock();
- screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object });
- screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1 });
+ screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1);
var windowImpl = MockWindowingPlatform.CreateWindowMock(400, 300);
windowImpl.Setup(x => x.DesktopScaling).Returns(1.75);
@@ -1146,9 +1146,9 @@ namespace Avalonia.Controls.UnitTests
private static Mock CreateImpl()
{
- var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
+ var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
var screens = new Mock();
- screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1);
var windowImpl = new Mock();
windowImpl.Setup(r => r.Compositor).Returns(RendererMocks.CreateDummyCompositor());
diff --git a/tests/Avalonia.Headless.XUnit.PerAssembly.UnitTests/Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj b/tests/Avalonia.Headless.XUnit.PerAssembly.UnitTests/Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj
index e638032870..270e078ed3 100644
--- a/tests/Avalonia.Headless.XUnit.PerAssembly.UnitTests/Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj
+++ b/tests/Avalonia.Headless.XUnit.PerAssembly.UnitTests/Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj
@@ -4,7 +4,6 @@
Exe
true
$(DefineConstants);XUNIT
- true
diff --git a/tests/Avalonia.Headless.XUnit.PerTest.UnitTests/Avalonia.Headless.XUnit.PerTest.UnitTests.csproj b/tests/Avalonia.Headless.XUnit.PerTest.UnitTests/Avalonia.Headless.XUnit.PerTest.UnitTests.csproj
index e638032870..270e078ed3 100644
--- a/tests/Avalonia.Headless.XUnit.PerTest.UnitTests/Avalonia.Headless.XUnit.PerTest.UnitTests.csproj
+++ b/tests/Avalonia.Headless.XUnit.PerTest.UnitTests/Avalonia.Headless.XUnit.PerTest.UnitTests.csproj
@@ -4,7 +4,6 @@
Exe
true
$(DefineConstants);XUNIT
- true
diff --git a/tests/Avalonia.IntegrationTests.Win32/Avalonia.IntegrationTests.Win32.csproj b/tests/Avalonia.IntegrationTests.Win32/Avalonia.IntegrationTests.Win32.csproj
index a11ecc1fb4..797265af46 100644
--- a/tests/Avalonia.IntegrationTests.Win32/Avalonia.IntegrationTests.Win32.csproj
+++ b/tests/Avalonia.IntegrationTests.Win32/Avalonia.IntegrationTests.Win32.csproj
@@ -13,10 +13,7 @@
-
-
-
-
+
diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs
index 0ff811ff22..11197888a5 100644
--- a/tests/Avalonia.LeakTests/ControlTests.cs
+++ b/tests/Avalonia.LeakTests/ControlTests.cs
@@ -402,9 +402,9 @@ namespace Avalonia.LeakTests
{
using (Start())
{
- var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
+ var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true);
var screens = new Mock();
- screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object);
+ screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1);
var impl = new Mock();
impl.Setup(r => r.TryGetFeature(It.IsAny())).Returns((object?)null);
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
index 051129e12c..727b3ddc45 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
@@ -639,8 +639,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
- var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
- var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ var compiledPath = ((CompiledBinding)column.Binding!).Path;
+ var node = Assert.IsType(Assert.Single(compiledPath!.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
Assert.Equal(nameof(TestData.StringProperty), node.Property.Name);
@@ -682,8 +682,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
- var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
- var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ var compiledPath = ((CompiledBinding)column.Binding!).Path;
+ var node = Assert.IsType(Assert.Single(compiledPath!.Elements));
Assert.Equal(typeof(int), node.Property.PropertyType);
// Assert DataGridLikeColumn.Template data type by evaluating the template.
@@ -727,8 +727,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
- var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
- var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ var compiledPath = ((CompiledBinding)column.Binding!).Path;
+ var node = Assert.IsType(Assert.Single(compiledPath!.Elements));
Assert.Equal(typeof(int), node.Property.PropertyType);
// Assert DataGridLikeColumn.Template data type by evaluating the template.
@@ -2060,9 +2060,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
x:DataType='local:TestDataContext'
X='{CompiledBinding StringProperty}' />";
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml);
- var compiledPath = ((CompiledBindingExtension)control.X!).Path;
+ var compiledPath = ((CompiledBinding)control.X!).Path;
- var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ var node = Assert.IsType(Assert.Single(compiledPath!.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
}
}
@@ -2078,9 +2078,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />";
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml);
- var compiledPath = ((CompiledBindingExtension)control.X!).Path;
+ var compiledPath = ((CompiledBinding)control.X!).Path;
- var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ var node = Assert.IsType(Assert.Single(compiledPath!.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
}
}
@@ -2097,9 +2097,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />";
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(new RuntimeXamlLoaderDocument(xaml),
new RuntimeXamlLoaderConfiguration { UseCompiledBindingsByDefault = true });
- var compiledPath = ((CompiledBindingExtension)control.X!).Path;
+ var compiledPath = ((CompiledBinding)control.X!).Path;
- var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ var node = Assert.IsType(Assert.Single(compiledPath!.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
}
}
diff --git a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs
index 45b8c5d2ce..deecc9eae3 100644
--- a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs
+++ b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs
@@ -385,6 +385,44 @@ namespace Avalonia.Skia.RenderTests
FontFamily = new FontFamily(symbolsFont)
};
}
+
+ [InlineData(TextRenderingMode.Antialias, TextHintingMode.None)]
+ [InlineData(TextRenderingMode.Alias, TextHintingMode.None)]
+ [InlineData(TextRenderingMode.Antialias, TextHintingMode.Light)]
+ [InlineData(TextRenderingMode.Alias, TextHintingMode.Light)]
+ [Win32Theory("Depends on the backend")]
+ public async Task Should_Render_TextBlock_With_TextOptions(
+ TextRenderingMode textRenderingMode,
+ TextHintingMode textHintingMode)
+ {
+ var textBlock = new TextBlock
+ {
+ FontFamily = TestFontFamily,
+ FontSize = 24,
+ Foreground = Brushes.Black,
+ Text = "TextOptions",
+ Background = Brushes.LightGray,
+ Padding = new Thickness(10)
+ };
+
+ TextOptions.SetTextOptions(textBlock, new TextOptions
+ {
+ TextRenderingMode = textRenderingMode,
+ TextHintingMode = textHintingMode
+ });
+
+ var target = new Border
+ {
+ Width = 300,
+ Height = 100,
+ Background = Brushes.White,
+ Child = textBlock
+ };
+
+ var testName = $"Should_Render_TextBlock_With_TextOptions_{textRenderingMode}_{textHintingMode}";
+ await RenderToFile(target, testName);
+ CompareImages(testName);
+ }
}
}
diff --git a/tests/Avalonia.RenderTests/Media/EffectTests.cs b/tests/Avalonia.RenderTests/Media/EffectTests.cs
index 9a83b397f4..c8b931dae8 100644
--- a/tests/Avalonia.RenderTests/Media/EffectTests.cs
+++ b/tests/Avalonia.RenderTests/Media/EffectTests.cs
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
using Avalonia.Media;
using Xunit;
#pragma warning disable CS0649
@@ -38,6 +39,43 @@ public class EffectTests : TestBase
await RenderToFile(target);
CompareImages(skipImmediate: true);
}
+
+ [Fact]
+ public async Task EffectFollowedByNonEffect()
+ {
+ var target = new Border
+ {
+ Background = Brushes.White,
+ Width = 200,
+ Height = 200,
+ Child = new Panel
+ {
+ Margin = new Thickness(25),
+ Children =
+ {
+ new Rectangle
+ {
+ Fill = Brushes.Yellow,
+ Effect = new DropShadowEffect
+ {
+ Opacity = 1,
+ OffsetX = 0,
+ OffsetY = 0,
+ Color = Colors.Black,
+ BlurRadius = 50
+ }
+ },
+ new Rectangle
+ {
+ Fill = new SolidColorBrush(0x7F007FFF)
+ }
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages(skipImmediate: true);
+ }
}
-#endif
\ No newline at end of file
+#endif
diff --git a/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs b/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs
index b28762d08d..ad0cf67d2f 100644
--- a/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs
+++ b/tests/Avalonia.RenderTests/Media/GlyphRunTests.cs
@@ -115,7 +115,7 @@ namespace Avalonia.Skia.RenderTests
[TextElement.ForegroundProperty] = new SolidColorBrush { Color = Colors.Black }
};
- RenderOptions.SetTextRenderingMode(control, TextRenderingMode.Alias);
+ TextOptions.SetTextRenderingMode(control, TextRenderingMode.Alias);
Decorator target = new Decorator
{
diff --git a/tests/Avalonia.Skia.UnitTests/Media/GlyphRunTests.cs b/tests/Avalonia.Skia.UnitTests/Media/GlyphRunTests.cs
index 1882ef9ccb..8f74f0779f 100644
--- a/tests/Avalonia.Skia.UnitTests/Media/GlyphRunTests.cs
+++ b/tests/Avalonia.Skia.UnitTests/Media/GlyphRunTests.cs
@@ -169,7 +169,7 @@ namespace Avalonia.Skia.UnitTests.Media
var glyphRun1 = CreateGlyphRun(shapedBuffer);
var bounds1 = glyphRun1.InkBounds;
- ((GlyphRunImpl)glyphRun1.PlatformImpl.Item).GetTextBlob(new RenderOptions { TextRenderingMode = TextRenderingMode.SubpixelAntialias });
+ ((GlyphRunImpl)glyphRun1.PlatformImpl.Item).GetTextBlob(new TextOptions { TextRenderingMode = TextRenderingMode.SubpixelAntialias }, default);
var bounds2 = CreateGlyphRun(shapedBuffer).InkBounds;
diff --git a/tests/Avalonia.Skia.UnitTests/TwoLevelCacheTests.cs b/tests/Avalonia.Skia.UnitTests/TwoLevelCacheTests.cs
new file mode 100644
index 0000000000..6946c7ec2b
--- /dev/null
+++ b/tests/Avalonia.Skia.UnitTests/TwoLevelCacheTests.cs
@@ -0,0 +1,351 @@
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using Avalonia.Skia;
+using Xunit;
+
+namespace Avalonia.Skia.UnitTests
+{
+ public class TwoLevelCacheTests
+ {
+ [Fact]
+ public void Constructor_WithNegativeSecondarySize_ThrowsArgumentOutOfRangeException()
+ {
+ Assert.Throws(() => new TwoLevelCache(-1));
+ }
+
+ [Fact]
+ public void Constructor_WithZeroSecondarySize_DoesNotThrow()
+ {
+ var cache = new TwoLevelCache(0);
+ Assert.NotNull(cache);
+ }
+
+ [Fact]
+ public void TryGet_EmptyCache_ReturnsFalse()
+ {
+ var cache = new TwoLevelCache();
+
+ var result = cache.TryGet("key", out var value);
+
+ Assert.False(result);
+ Assert.Null(value);
+ }
+
+ [Fact]
+ public void GetOrAdd_FirstItem_StoresInPrimary()
+ {
+ var cache = new TwoLevelCache();
+ var value = new object();
+
+ var result = cache.GetOrAdd("key1", _ => value);
+
+ Assert.Same(value, result);
+ Assert.True(cache.TryGet("key1", out var retrieved));
+ Assert.Same(value, retrieved);
+ }
+
+ [Fact]
+ public void GetOrAdd_SameKey_ReturnsExistingValue()
+ {
+ var cache = new TwoLevelCache();
+ var value1 = new object();
+ var value2 = new object();
+
+ cache.GetOrAdd("key", _ => value1);
+ var result = cache.GetOrAdd("key", _ => value2);
+
+ Assert.Same(value1, result);
+ }
+
+ [Fact]
+ public void GetOrAdd_SecondItem_StoresInSecondary()
+ {
+ var cache = new TwoLevelCache(secondarySize: 3);
+ var value1 = new object();
+ var value2 = new object();
+
+ cache.GetOrAdd("key1", _ => value1);
+ cache.GetOrAdd("key2", _ => value2);
+
+ Assert.True(cache.TryGet("key1", out var retrieved1));
+ Assert.Same(value1, retrieved1);
+ Assert.True(cache.TryGet("key2", out var retrieved2));
+ Assert.Same(value2, retrieved2);
+ }
+
+ [Fact]
+ public void GetOrAdd_MultipleItems_StoresCorrectly()
+ {
+ var cache = new TwoLevelCache(secondarySize: 3);
+ var values = new object[4];
+ for (int i = 0; i < 4; i++)
+ {
+ values[i] = new object();
+ cache.GetOrAdd($"key{i}", _ => values[i]);
+ }
+
+ // All should be retrievable
+ for (int i = 0; i < 4; i++)
+ {
+ Assert.True(cache.TryGet($"key{i}", out var retrieved));
+ Assert.Same(values[i], retrieved);
+ }
+ }
+
+ [Fact]
+ public void GetOrAdd_ExceedsCapacity_CallsEvictionAction()
+ {
+ var evictedValues = new List