Browse Source

Merge branch 'master' into FixTabWidth

pull/9897/head
Sergey Mikolaytis 4 years ago
committed by GitHub
parent
commit
158181c2d9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .editorconfig
  2. 16
      azure-pipelines-integrationtests.yml
  3. 24
      azure-pipelines.yml
  4. 6
      global.json
  5. 2
      samples/ControlCatalog.Android/MainActivity.cs
  6. 4
      samples/ControlCatalog.Android/Resources/values/styles.xml
  7. 2
      samples/ControlCatalog.Android/SplashActivity.cs
  8. 13
      samples/ControlCatalog.Browser/Properties/launchSettings.json
  9. 3
      samples/ControlCatalog/MainView.xaml
  10. 23
      samples/ControlCatalog/MainView.xaml.cs
  11. 1
      samples/ControlCatalog/MainWindow.xaml
  12. 2
      samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs
  13. 7
      samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml
  14. 9
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  15. 2
      src/Android/Avalonia.Android/AvaloniaView.cs
  16. 1
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  17. 85
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  18. 21
      src/Avalonia.Base/Controls/NameScopeExtensions.cs
  19. 2
      src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs
  20. 12
      src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs
  21. 18
      src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
  22. 2
      src/Avalonia.Base/Media/TextFormatting/TextEllipsisHelper.cs
  23. 28
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  24. 4
      src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs
  25. 40
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  26. 2
      src/Avalonia.Base/Media/TextFormatting/TextRun.cs
  27. 16
      src/Avalonia.Base/Media/TextFormatting/UnshapedTextRun.cs
  28. 2
      src/Avalonia.Base/Rendering/Composition/Compositor.cs
  29. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
  30. 6
      src/Avalonia.Base/Rendering/Composition/Server/ServerCustomCompositionVisual.cs
  31. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs
  32. 8
      src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs
  33. 2
      src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs
  34. 1
      src/Avalonia.Base/Visual.cs
  35. 4
      src/Avalonia.Build.Tasks/ComInteropHelper.cs
  36. 4
      src/Avalonia.Controls.ColorPicker/ColorPalettes/FlatColorPalette.cs
  37. 4
      src/Avalonia.Controls.ColorPicker/ColorPalettes/FlatHalfColorPalette.cs
  38. 4
      src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs
  39. 4
      src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialHalfColorPalette.cs
  40. 2
      src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
  41. 2
      src/Avalonia.Controls.DataGrid/DataGridColumn.cs
  42. 1
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  43. 4
      src/Avalonia.Controls/BorderVisual.cs
  44. 8
      src/Avalonia.Controls/Control.cs
  45. 2
      src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs
  46. 1
      src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
  47. 4
      src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs
  48. 4
      src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs
  49. 6
      src/Avalonia.Controls/TransitioningContentControl.cs
  50. 8
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs
  51. 1
      src/Browser/Avalonia.Browser.Blazor/Avalonia.Browser.Blazor.csproj
  52. 3
      src/Browser/Avalonia.Browser.Blazor/AvaloniaView.cs
  53. 1
      src/Browser/Avalonia.Browser.Blazor/BlazorSingleViewLifetime.cs
  54. 1
      src/Browser/Avalonia.Browser/AvaloniaView.cs
  55. 2
      src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs
  56. 12
      src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
  57. 1
      src/Browser/Avalonia.Browser/Interop/CanvasHelper.cs
  58. 14
      src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpuRenderTarget.cs
  59. 1
      src/Browser/Avalonia.Browser/Storage/BlobReadableStream.cs
  60. 1
      src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs
  61. 1
      src/Browser/Avalonia.Browser/Storage/WriteableStream.cs
  62. 1
      src/Browser/Avalonia.Browser/webapp/modules/avalonia/dom.ts
  63. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  64. 12
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  65. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs
  66. 2
      src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs
  67. 2
      src/tools/DevAnalyzers/GenericVirtualAnalyzer.cs
  68. 6
      src/tools/DevGenerators/CompositionGenerator/Generator.cs
  69. 4
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs
  70. 28
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs
  71. 30
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

2
.editorconfig

@ -169,6 +169,8 @@ dotnet_diagnostic.CA1828.severity = warning
dotnet_diagnostic.CA1829.severity = warning dotnet_diagnostic.CA1829.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning dotnet_diagnostic.CA1847.severity = warning
#CACA2211:Non-constant fields should not be visible
dotnet_diagnostic.CA2211.severity = error
# Wrapping preferences # Wrapping preferences
csharp_wrap_before_ternary_opsigns = false csharp_wrap_before_ternary_opsigns = false

16
azure-pipelines-integrationtests.yml

@ -13,14 +13,14 @@ jobs:
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.401' displayName: 'Use .NET Core SDK 6.0.404'
inputs: inputs:
version: 6.0.401 version: 6.0.404
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100' displayName: 'Use .NET Core SDK 7.0.101'
inputs: inputs:
version: 7.0.100 version: 7.0.101
- script: system_profiler SPDisplaysDataType |grep Resolution - script: system_profiler SPDisplaysDataType |grep Resolution
@ -51,14 +51,14 @@ jobs:
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.401' displayName: 'Use .NET Core SDK 6.0.404'
inputs: inputs:
version: 6.0.401 version: 6.0.404
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100' displayName: 'Use .NET Core SDK 7.0.101'
inputs: inputs:
version: 7.0.100 version: 7.0.101
- task: Windows Application Driver@0 - task: Windows Application Driver@0
inputs: inputs:

24
azure-pipelines.yml

@ -30,14 +30,14 @@ jobs:
vmImage: 'ubuntu-20.04' vmImage: 'ubuntu-20.04'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.401' displayName: 'Use .NET Core SDK 6.0.404'
inputs: inputs:
version: 6.0.401 version: 6.0.404
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0' displayName: 'Use .NET Core SDK 7.0.101'
inputs: inputs:
version: 7.0.100 version: 7.0.101
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'
@ -67,14 +67,14 @@ jobs:
vmImage: 'macos-12' vmImage: 'macos-12'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.401' displayName: 'Use .NET Core SDK 6.0.404'
inputs: inputs:
version: 6.0.401 version: 6.0.404
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100' displayName: 'Use .NET Core SDK 7.0.101'
inputs: inputs:
version: 7.0.100 version: 7.0.101
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'
@ -138,14 +138,14 @@ jobs:
SolutionDir: '$(Build.SourcesDirectory)' SolutionDir: '$(Build.SourcesDirectory)'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 6.0.401' displayName: 'Use .NET Core SDK 6.0.404'
inputs: inputs:
version: 6.0.401 version: 6.0.404
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100' displayName: 'Use .NET Core SDK 7.0.101'
inputs: inputs:
version: 7.0.100 version: 7.0.101
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'

6
global.json

@ -1,11 +1,9 @@
{ {
"sdk": { "sdk": {
"version": "7.0.100", "version": "7.0.101",
"rollForward": "latestFeature" "rollForward": "latestFeature"
}, },
"msbuild-sdks": { "msbuild-sdks": {
"Microsoft.Build.Traversal": "1.0.43", "Microsoft.Build.Traversal": "1.0.43"
"MSBuild.Sdk.Extras": "3.0.22",
"AggregatePackage.NuGet.Sdk" : "0.1.12"
} }
} }

2
samples/ControlCatalog.Android/MainActivity.cs

@ -5,7 +5,7 @@ using Avalonia.Android;
namespace ControlCatalog.Android namespace ControlCatalog.Android
{ {
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
public class MainActivity : AvaloniaMainActivity public class MainActivity : AvaloniaMainActivity
{ {
} }

4
samples/ControlCatalog.Android/Resources/values/styles.xml

@ -14,4 +14,8 @@
<item name="android:windowContentOverlay">@null</item> <item name="android:windowContentOverlay">@null</item>
</style> </style>
<style name="MyTheme.Main" parent ="MyTheme.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
</style>
</resources> </resources>

2
samples/ControlCatalog.Android/SplashActivity.cs

@ -28,6 +28,8 @@ namespace ControlCatalog.Android
base.OnResume(); base.OnResume();
StartActivity(new Intent(Application.Context, typeof(MainActivity))); StartActivity(new Intent(Application.Context, typeof(MainActivity)));
Finish();
} }
} }
} }

13
samples/ControlCatalog.Browser/Properties/launchSettings.json

@ -0,0 +1,13 @@
{
"profiles": {
"ControlCatalog.Browser": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/debug?browser={browserInspectUri}"
}
}
}

3
samples/ControlCatalog/MainView.xaml

@ -209,8 +209,7 @@
</ComboBox.Items> </ComboBox.Items>
</ComboBox> </ComboBox>
<ComboBox x:Name="TransparencyLevels" <ComboBox x:Name="TransparencyLevels"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch">
SelectedIndex="{Binding TransparencyLevel}">
<ComboBox.Items> <ComboBox.Items>
<WindowTransparencyLevel>None</WindowTransparencyLevel> <WindowTransparencyLevel>None</WindowTransparencyLevel>
<WindowTransparencyLevel>Transparent</WindowTransparencyLevel> <WindowTransparencyLevel>Transparent</WindowTransparencyLevel>

23
samples/ControlCatalog/MainView.xaml.cs

@ -6,6 +6,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Immutable; using Avalonia.Media.Immutable;
using Avalonia.VisualTree;
using ControlCatalog.Models; using ControlCatalog.Models;
using ControlCatalog.Pages; using ControlCatalog.Pages;
@ -59,17 +60,25 @@ namespace ControlCatalog
}; };
var transparencyLevels = this.Get<ComboBox>("TransparencyLevels"); var transparencyLevels = this.Get<ComboBox>("TransparencyLevels");
IDisposable? backgroundSetter = null, paneBackgroundSetter = null; IDisposable? topLevelBackgroundSideSetter = null, sideBarBackgroundSetter = null, paneBackgroundSetter = null;
transparencyLevels.SelectionChanged += (sender, e) => transparencyLevels.SelectionChanged += (sender, e) =>
{ {
backgroundSetter?.Dispose(); topLevelBackgroundSideSetter?.Dispose();
sideBarBackgroundSetter?.Dispose();
paneBackgroundSetter?.Dispose(); paneBackgroundSetter?.Dispose();
if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected)
&& selected != WindowTransparencyLevel.None)
{ {
var semiTransparentBrush = new ImmutableSolidColorBrush(Colors.Gray, 0.5); var topLevel = (TopLevel)this.GetVisualRoot()!;
backgroundSetter = sideBar.SetValue(BackgroundProperty, semiTransparentBrush, Avalonia.Data.BindingPriority.Style); topLevel.TransparencyLevelHint = selected;
paneBackgroundSetter = sideBar.SetValue(SplitView.PaneBackgroundProperty, semiTransparentBrush, Avalonia.Data.BindingPriority.Style);
if (selected != WindowTransparencyLevel.None)
{
var transparentBrush = new ImmutableSolidColorBrush(Colors.White, 0);
var semiTransparentBrush = new ImmutableSolidColorBrush(Colors.Gray, 0.2);
topLevelBackgroundSideSetter = topLevel.SetValue(BackgroundProperty, transparentBrush, Avalonia.Data.BindingPriority.Style);
sideBarBackgroundSetter = sideBar.SetValue(BackgroundProperty, semiTransparentBrush, Avalonia.Data.BindingPriority.Style);
paneBackgroundSetter = sideBar.SetValue(SplitView.PaneBackgroundProperty, semiTransparentBrush, Avalonia.Data.BindingPriority.Style);
}
} }
}; };
} }

1
samples/ControlCatalog/MainWindow.xaml

@ -10,7 +10,6 @@
ExtendClientAreaToDecorationsHint="{Binding ExtendClientAreaEnabled}" ExtendClientAreaToDecorationsHint="{Binding ExtendClientAreaEnabled}"
ExtendClientAreaChromeHints="{Binding ChromeHints}" ExtendClientAreaChromeHints="{Binding ChromeHints}"
ExtendClientAreaTitleBarHeightHint="{Binding TitleBarHeight}" ExtendClientAreaTitleBarHeightHint="{Binding TitleBarHeight}"
TransparencyLevelHint="{Binding TransparencyLevel}"
x:Name="MainWindow" x:Name="MainWindow"
Background="Transparent" Background="Transparent"
x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}"

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

@ -17,7 +17,7 @@ namespace ControlCatalog.Pages
this.Get<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " + this.Get<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " +
"to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " + "to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " +
"are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + "are easy to use with touch or mouse, and they can be styled and configured in several different ways. " +
"12 - hour or 24 - hour clock and visiblility of AM / PM is dynamically set based on user time settings, or can be overridden."; "12 - hour or 24 - hour clock and visibility of AM / PM is dynamically set based on user time settings, or can be overridden.";
} }

7
samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml

@ -11,12 +11,5 @@
<CheckBox Content="Title Bar" IsChecked="{Binding SystemTitleBarEnabled}" /> <CheckBox Content="Title Bar" IsChecked="{Binding SystemTitleBarEnabled}" />
<CheckBox Content="Prefer System Chrome" IsChecked="{Binding PreferSystemChromeEnabled}" /> <CheckBox Content="Prefer System Chrome" IsChecked="{Binding PreferSystemChromeEnabled}" />
<Slider Minimum="-1" Maximum="200" Value="{Binding TitleBarHeight}" /> <Slider Minimum="-1" Maximum="200" Value="{Binding TitleBarHeight}" />
<ComboBox x:Name="TransparencyLevels" SelectedIndex="{Binding TransparencyLevel}">
<ComboBoxItem>None</ComboBoxItem>
<ComboBoxItem>Transparent</ComboBoxItem>
<ComboBoxItem>Blur</ComboBoxItem>
<ComboBoxItem>AcrylicBlur</ComboBoxItem>
<ComboBoxItem>Mica</ComboBoxItem>
</ComboBox>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

9
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -12,12 +12,9 @@ namespace ControlCatalog.ViewModels
{ {
class MainWindowViewModel : ViewModelBase class MainWindowViewModel : ViewModelBase
{ {
private IManagedNotificationManager _notificationManager;
private bool _isMenuItemChecked = true; private bool _isMenuItemChecked = true;
private WindowState _windowState; private WindowState _windowState;
private WindowState[] _windowStates = Array.Empty<WindowState>(); private WindowState[] _windowStates = Array.Empty<WindowState>();
private int _transparencyLevel;
private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome; private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome;
private bool _extendClientAreaEnabled; private bool _extendClientAreaEnabled;
private bool _systemTitleBarEnabled; private bool _systemTitleBarEnabled;
@ -77,12 +74,6 @@ namespace ControlCatalog.ViewModels
TitleBarHeight = -1; TitleBarHeight = -1;
} }
public int TransparencyLevel
{
get { return _transparencyLevel; }
set { this.RaiseAndSetIfChanged(ref _transparencyLevel, value); }
}
public ExtendClientAreaChromeHints ChromeHints public ExtendClientAreaChromeHints ChromeHints
{ {
get { return _chromeHints; } get { return _chromeHints; }

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

@ -24,6 +24,8 @@ namespace Avalonia.Android
_root = new EmbeddableControlRoot(_view); _root = new EmbeddableControlRoot(_view);
_root.Prepare(); _root.Prepare();
this.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
} }
internal TopLevelImpl TopLevelImpl => _view; internal TopLevelImpl TopLevelImpl => _view;

1
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -22,6 +22,7 @@ namespace Avalonia.Android
public InvalidationAwareSurfaceView(Context context) : base(context) public InvalidationAwareSurfaceView(Context context) : base(context)
{ {
Holder.AddCallback(this); Holder.AddCallback(this);
Holder.SetFormat(global::Android.Graphics.Format.Transparent);
_handler = new Handler(context.MainLooper); _handler = new Handler(context.MainLooper);
} }

85
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -26,6 +26,7 @@ using Avalonia.Rendering.Composition;
using Java.Lang; using Java.Lang;
using Math = System.Math; using Math = System.Math;
using AndroidRect = Android.Graphics.Rect; using AndroidRect = Android.Graphics.Rect;
using Android.Graphics.Drawables;
namespace Avalonia.Android.Platform.SkiaPlatform namespace Avalonia.Android.Platform.SkiaPlatform
{ {
@ -283,7 +284,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public Action LostFocus { get; set; } public Action LostFocus { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; } public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None; public WindowTransparencyLevel TransparencyLevel { get; private set; }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1);
@ -301,7 +302,87 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{ {
throw new NotImplementedException(); if (TransparencyLevel != transparencyLevel)
{
bool isBelowR = Build.VERSION.SdkInt < BuildVersionCodes.R;
bool isAboveR = Build.VERSION.SdkInt > BuildVersionCodes.R;
if (_view.Context is AvaloniaMainActivity activity)
{
switch (transparencyLevel)
{
case WindowTransparencyLevel.AcrylicBlur:
case WindowTransparencyLevel.ForceAcrylicBlur:
case WindowTransparencyLevel.Mica:
case WindowTransparencyLevel.None:
if (!isBelowR)
{
activity.SetTranslucent(false);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
activity.Window.Attributes = attr;
}
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
if(transparencyLevel != WindowTransparencyLevel.None)
{
return;
}
break;
case WindowTransparencyLevel.Transparent:
if (!isBelowR)
{
activity.SetTranslucent(true);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
activity.Window.Attributes = attr;
}
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
break;
case WindowTransparencyLevel.Blur:
if (isAboveR)
{
activity.SetTranslucent(true);
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 120;
activity.Window.Attributes = attr;
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
else
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
return;
}
break;
}
TransparencyLevel = transparencyLevel;
}
}
} }
} }

21
src/Avalonia.Base/Controls/NameScopeExtensions.cs

@ -25,13 +25,18 @@ namespace Avalonia.Controls
var result = nameScope.Find(name); var result = nameScope.Find(name);
if (result != null && !(result is T)) if (result == null)
{ {
throw new InvalidOperationException( return null;
$"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'.");
} }
return (T?)result; if (result is T typed)
{
return typed;
}
throw new InvalidOperationException(
$"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'.");
} }
/// <summary> /// <summary>
@ -74,13 +79,13 @@ namespace Avalonia.Controls
throw new KeyNotFoundException($"Could not find control '{name}'."); throw new KeyNotFoundException($"Could not find control '{name}'.");
} }
if (!(result is T)) if (result is T typed)
{ {
throw new InvalidOperationException( return typed;
$"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'.");
} }
return (T)result; throw new InvalidOperationException(
$"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'.");
} }
/// <summary> /// <summary>

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

@ -91,7 +91,7 @@ namespace Avalonia.Media.TextFormatting
continue; continue;
} }
if (textRun is ShapedTextCharacters shapedText) if (textRun is ShapedTextRun shapedText)
{ {
var glyphRun = shapedText.GlyphRun; var glyphRun = shapedText.GlyphRun;
var shapedBuffer = shapedText.ShapedBuffer; var shapedBuffer = shapedText.ShapedBuffer;

12
src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs → src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs

@ -6,11 +6,11 @@ namespace Avalonia.Media.TextFormatting
/// <summary> /// <summary>
/// A text run that holds shaped characters. /// A text run that holds shaped characters.
/// </summary> /// </summary>
public sealed class ShapedTextCharacters : DrawableTextRun public sealed class ShapedTextRun : DrawableTextRun
{ {
private GlyphRun? _glyphRun; private GlyphRun? _glyphRun;
public ShapedTextCharacters(ShapedBuffer shapedBuffer, TextRunProperties properties) public ShapedTextRun(ShapedBuffer shapedBuffer, TextRunProperties properties)
{ {
ShapedBuffer = shapedBuffer; ShapedBuffer = shapedBuffer;
CharacterBufferReference = shapedBuffer.CharacterBufferRange.CharacterBufferReference; CharacterBufferReference = shapedBuffer.CharacterBufferRange.CharacterBufferReference;
@ -155,7 +155,7 @@ namespace Avalonia.Media.TextFormatting
return length > 0; return length > 0;
} }
internal SplitResult<ShapedTextCharacters> Split(int length) internal SplitResult<ShapedTextRun> Split(int length)
{ {
if (IsReversed) if (IsReversed)
{ {
@ -171,7 +171,7 @@ namespace Avalonia.Media.TextFormatting
var splitBuffer = ShapedBuffer.Split(length); var splitBuffer = ShapedBuffer.Split(length);
var first = new ShapedTextCharacters(splitBuffer.First, Properties); var first = new ShapedTextRun(splitBuffer.First, Properties);
#if DEBUG #if DEBUG
@ -182,9 +182,9 @@ namespace Avalonia.Media.TextFormatting
#endif #endif
var second = new ShapedTextCharacters(splitBuffer.Second!, Properties); var second = new ShapedTextRun(splitBuffer.Second!, Properties);
return new SplitResult<ShapedTextCharacters>(first, second); return new SplitResult<ShapedTextRun>(first, second);
} }
internal GlyphRun CreateGlyphRun() internal GlyphRun CreateGlyphRun()

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

@ -91,12 +91,12 @@ namespace Avalonia.Media.TextFormatting
public override TextRunProperties Properties { get; } public override TextRunProperties Properties { get; }
/// <summary> /// <summary>
/// Gets a list of <see cref="ShapeableTextCharacters"/>. /// Gets a list of <see cref="UnshapedTextRun"/>.
/// </summary> /// </summary>
/// <returns>The shapeable text characters.</returns> /// <returns>The shapeable text characters.</returns>
internal IReadOnlyList<ShapeableTextCharacters> GetShapeableCharacters(CharacterBufferRange characterBufferRange, sbyte biDiLevel, ref TextRunProperties? previousProperties) internal IReadOnlyList<UnshapedTextRun> GetShapeableCharacters(CharacterBufferRange characterBufferRange, sbyte biDiLevel, ref TextRunProperties? previousProperties)
{ {
var shapeableCharacters = new List<ShapeableTextCharacters>(2); var shapeableCharacters = new List<UnshapedTextRun>(2);
while (characterBufferRange.Length > 0) while (characterBufferRange.Length > 0)
{ {
@ -120,7 +120,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="biDiLevel">The bidi level of the run.</param> /// <param name="biDiLevel">The bidi level of the run.</param>
/// <param name="previousProperties"></param> /// <param name="previousProperties"></param>
/// <returns>A list of shapeable text runs.</returns> /// <returns>A list of shapeable text runs.</returns>
private static ShapeableTextCharacters CreateShapeableRun(CharacterBufferRange characterBufferRange, private static UnshapedTextRun CreateShapeableRun(CharacterBufferRange characterBufferRange,
TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties? previousProperties) TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties? previousProperties)
{ {
var defaultTypeface = defaultProperties.Typeface; var defaultTypeface = defaultProperties.Typeface;
@ -133,12 +133,12 @@ namespace Avalonia.Media.TextFormatting
{ {
if (TryGetShapeableLength(characterBufferRange, previousTypeface.Value, null, out var fallbackCount, out _)) if (TryGetShapeableLength(characterBufferRange, previousTypeface.Value, null, out var fallbackCount, out _))
{ {
return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, fallbackCount, return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, fallbackCount,
defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel); defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel);
} }
} }
return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface), return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface),
biDiLevel); biDiLevel);
} }
@ -146,7 +146,7 @@ namespace Avalonia.Media.TextFormatting
{ {
if (TryGetShapeableLength(characterBufferRange, previousTypeface.Value, defaultTypeface, out count, out _)) if (TryGetShapeableLength(characterBufferRange, previousTypeface.Value, defaultTypeface, out count, out _))
{ {
return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count,
defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel); defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel);
} }
} }
@ -176,7 +176,7 @@ namespace Avalonia.Media.TextFormatting
if (matchFound && TryGetShapeableLength(characterBufferRange, currentTypeface, defaultTypeface, out count, out _)) if (matchFound && TryGetShapeableLength(characterBufferRange, currentTypeface, defaultTypeface, out count, out _))
{ {
//Fallback found //Fallback found
return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface), return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface),
biDiLevel); biDiLevel);
} }
@ -199,7 +199,7 @@ namespace Avalonia.Media.TextFormatting
count += grapheme.Text.Length; count += grapheme.Text.Length;
} }
return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, defaultProperties, biDiLevel); return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties, biDiLevel);
} }
/// <summary> /// <summary>

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

@ -31,7 +31,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
currentWidth += shapedRun.Size.Width; currentWidth += shapedRun.Size.Width;

28
src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs

@ -124,7 +124,7 @@ namespace Avalonia.Media.TextFormatting
var second = new List<DrawableTextRun>(secondCount); var second = new List<DrawableTextRun>(secondCount);
if (currentRun is ShapedTextCharacters shapedTextCharacters) if (currentRun is ShapedTextRun shapedTextCharacters)
{ {
var split = shapedTextCharacters.Split(length - currentLength); var split = shapedTextCharacters.Split(length - currentLength);
@ -206,16 +206,16 @@ namespace Avalonia.Media.TextFormatting
break; break;
} }
case ShapeableTextCharacters shapeableRun: case UnshapedTextRun shapeableRun:
{ {
var groupedRuns = new List<ShapeableTextCharacters>(2) { shapeableRun }; var groupedRuns = new List<UnshapedTextRun>(2) { shapeableRun };
var characterBufferReference = currentRun.CharacterBufferReference; var characterBufferReference = currentRun.CharacterBufferReference;
var length = currentRun.Length; var length = currentRun.Length;
var offsetToFirstCharacter = characterBufferReference.OffsetToFirstChar; var offsetToFirstCharacter = characterBufferReference.OffsetToFirstChar;
while (index + 1 < processedRuns.Count) while (index + 1 < processedRuns.Count)
{ {
if (processedRuns[index + 1] is not ShapeableTextCharacters nextRun) if (processedRuns[index + 1] is not UnshapedTextRun nextRun)
{ {
break; break;
} }
@ -258,10 +258,10 @@ namespace Avalonia.Media.TextFormatting
return drawableTextRuns; return drawableTextRuns;
} }
private static IReadOnlyList<ShapedTextCharacters> ShapeTogether( private static IReadOnlyList<ShapedTextRun> ShapeTogether(
IReadOnlyList<ShapeableTextCharacters> textRuns, CharacterBufferReference text, int length, TextShaperOptions options) IReadOnlyList<UnshapedTextRun> textRuns, CharacterBufferReference text, int length, TextShaperOptions options)
{ {
var shapedRuns = new List<ShapedTextCharacters>(textRuns.Count); var shapedRuns = new List<ShapedTextRun>(textRuns.Count);
var shapedBuffer = TextShaper.Current.ShapeText(text, length, options); var shapedBuffer = TextShaper.Current.ShapeText(text, length, options);
@ -271,7 +271,7 @@ namespace Avalonia.Media.TextFormatting
var splitResult = shapedBuffer.Split(currentRun.Length); var splitResult = shapedBuffer.Split(currentRun.Length);
shapedRuns.Add(new ShapedTextCharacters(splitResult.First, currentRun.Properties)); shapedRuns.Add(new ShapedTextRun(splitResult.First, currentRun.Properties));
shapedBuffer = splitResult.Second!; shapedBuffer = splitResult.Second!;
} }
@ -280,9 +280,9 @@ namespace Avalonia.Media.TextFormatting
} }
/// <summary> /// <summary>
/// Coalesces ranges of the same bidi level to form <see cref="ShapeableTextCharacters"/> /// Coalesces ranges of the same bidi level to form <see cref="UnshapedTextRun"/>
/// </summary> /// </summary>
/// <param name="textCharacters">The text characters to form <see cref="ShapeableTextCharacters"/> from.</param> /// <param name="textCharacters">The text characters to form <see cref="UnshapedTextRun"/> from.</param>
/// <param name="levels">The bidi levels.</param> /// <param name="levels">The bidi levels.</param>
/// <returns></returns> /// <returns></returns>
private static IEnumerable<IReadOnlyList<TextRun>> CoalesceLevels(IReadOnlyList<TextRun> textCharacters, ArraySlice<sbyte> levels) private static IEnumerable<IReadOnlyList<TextRun>> CoalesceLevels(IReadOnlyList<TextRun> textCharacters, ArraySlice<sbyte> levels)
@ -474,7 +474,7 @@ namespace Avalonia.Media.TextFormatting
{ {
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedTextCharacters: case ShapedTextRun shapedTextCharacters:
{ {
if(shapedTextCharacters.ShapedBuffer.Length > 0) if(shapedTextCharacters.ShapedBuffer.Length > 0)
{ {
@ -538,7 +538,7 @@ namespace Avalonia.Media.TextFormatting
var shapedBuffer = new ShapedBuffer(characterBufferRange, glyphInfos, glyphTypeface, properties.FontRenderingEmSize, var shapedBuffer = new ShapedBuffer(characterBufferRange, glyphInfos, glyphTypeface, properties.FontRenderingEmSize,
(sbyte)flowDirection); (sbyte)flowDirection);
var textRuns = new List<DrawableTextRun> { new ShapedTextCharacters(shapedBuffer, properties) }; var textRuns = new List<DrawableTextRun> { new ShapedTextRun(shapedBuffer, properties) };
return new TextLineImpl(textRuns, firstTextSourceIndex, 0, paragraphWidth, paragraphProperties, flowDirection).FinalizeLine(); return new TextLineImpl(textRuns, firstTextSourceIndex, 0, paragraphWidth, paragraphProperties, flowDirection).FinalizeLine();
} }
@ -744,7 +744,7 @@ namespace Avalonia.Media.TextFormatting
/// <returns> /// <returns>
/// The shaped symbol. /// The shaped symbol.
/// </returns> /// </returns>
internal static ShapedTextCharacters CreateSymbol(TextRun textRun, FlowDirection flowDirection) internal static ShapedTextRun CreateSymbol(TextRun textRun, FlowDirection flowDirection)
{ {
var textShaper = TextShaper.Current; var textShaper = TextShaper.Current;
@ -760,7 +760,7 @@ namespace Avalonia.Media.TextFormatting
var shapedBuffer = textShaper.ShapeText(characterBuffer, textRun.Length, shaperOptions); var shapedBuffer = textShaper.ShapeText(characterBuffer, textRun.Length, shaperOptions);
return new ShapedTextCharacters(shapedBuffer, textRun.Properties); return new ShapedTextRun(shapedBuffer, textRun.Properties);
} }
} }
} }

4
src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs

@ -65,7 +65,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
currentWidth += currentRun.Size.Width; currentWidth += currentRun.Size.Width;
@ -118,7 +118,7 @@ namespace Avalonia.Media.TextFormatting
switch (run) switch (run)
{ {
case ShapedTextCharacters endShapedRun: case ShapedTextRun endShapedRun:
{ {
if (endShapedRun.TryMeasureCharactersBackwards(availableSuffixWidth, if (endShapedRun.TryMeasureCharactersBackwards(availableSuffixWidth,
out var suffixCount, out var suffixWidth)) out var suffixCount, out var suffixWidth))

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

@ -192,14 +192,14 @@ namespace Avalonia.Media.TextFormatting
{ {
var currentRun = _textRuns[i]; var currentRun = _textRuns[i];
if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) if (currentRun is ShapedTextRun shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight)
{ {
var rightToLeftIndex = i; var rightToLeftIndex = i;
currentPosition += currentRun.Length; currentPosition += currentRun.Length;
while (rightToLeftIndex + 1 <= _textRuns.Count - 1) while (rightToLeftIndex + 1 <= _textRuns.Count - 1)
{ {
var nextShaped = _textRuns[++rightToLeftIndex] as ShapedTextCharacters; var nextShaped = _textRuns[++rightToLeftIndex] as ShapedTextRun;
if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight) if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight)
{ {
@ -255,7 +255,7 @@ namespace Avalonia.Media.TextFormatting
switch (run) switch (run)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _);
@ -303,7 +303,7 @@ namespace Avalonia.Media.TextFormatting
{ {
var currentRun = _textRuns[index]; var currentRun = _textRuns[index];
if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) if (currentRun is ShapedTextRun shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight)
{ {
var i = index; var i = index;
@ -313,7 +313,7 @@ namespace Avalonia.Media.TextFormatting
{ {
var nextRun = _textRuns[i + 1]; var nextRun = _textRuns[i + 1];
if (nextRun is ShapedTextCharacters nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight) if (nextRun is ShapedTextRun nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight)
{ {
i++; i++;
@ -407,7 +407,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedTextCharacters: case ShapedTextRun shapedTextCharacters:
{ {
currentGlyphRun = shapedTextCharacters.GlyphRun; currentGlyphRun = shapedTextCharacters.GlyphRun;
@ -476,7 +476,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
nextCharacterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(characterHit); nextCharacterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(characterHit);
break; break;
@ -550,7 +550,7 @@ namespace Avalonia.Media.TextFormatting
double combinedWidth; double combinedWidth;
if (currentRun is ShapedTextCharacters currentShapedRun) if (currentRun is ShapedTextRun currentShapedRun)
{ {
var firstCluster = currentShapedRun.GlyphRun.Metrics.FirstCluster; var firstCluster = currentShapedRun.GlyphRun.Metrics.FirstCluster;
@ -592,7 +592,7 @@ namespace Avalonia.Media.TextFormatting
var rightToLeftIndex = index; var rightToLeftIndex = index;
var rightToLeftWidth = currentShapedRun.Size.Width; var rightToLeftWidth = currentShapedRun.Size.Width;
while (rightToLeftIndex + 1 <= _textRuns.Count - 1 && _textRuns[rightToLeftIndex + 1] is ShapedTextCharacters nextShapedRun) while (rightToLeftIndex + 1 <= _textRuns.Count - 1 && _textRuns[rightToLeftIndex + 1] is ShapedTextRun nextShapedRun)
{ {
if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight) if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight)
{ {
@ -624,12 +624,12 @@ namespace Avalonia.Media.TextFormatting
for (int i = rightToLeftIndex - 1; i >= index; i--) for (int i = rightToLeftIndex - 1; i >= index; i--)
{ {
if (TextRuns[i] is not ShapedTextCharacters) if (TextRuns[i] is not ShapedTextRun)
{ {
continue; continue;
} }
currentShapedRun = (ShapedTextCharacters)TextRuns[i]; currentShapedRun = (ShapedTextRun)TextRuns[i];
currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength); currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength);
@ -769,7 +769,7 @@ namespace Avalonia.Media.TextFormatting
var characterLength = 0; var characterLength = 0;
var endX = startX; var endX = startX;
if (currentRun is ShapedTextCharacters currentShapedRun) if (currentRun is ShapedTextRun currentShapedRun)
{ {
var offset = Math.Max(0, firstTextSourceIndex - currentPosition); var offset = Math.Max(0, firstTextSourceIndex - currentPosition);
@ -883,7 +883,7 @@ namespace Avalonia.Media.TextFormatting
return result; return result;
} }
private TextRunBounds GetRightToLeftTextRunBounds(ShapedTextCharacters currentRun, double endX, int firstTextSourceIndex, int characterIndex, int currentPosition, int remainingLength) private TextRunBounds GetRightToLeftTextRunBounds(ShapedTextRun currentRun, double endX, int firstTextSourceIndex, int characterIndex, int currentPosition, int remainingLength)
{ {
var startX = endX; var startX = endX;
@ -945,7 +945,7 @@ namespace Avalonia.Media.TextFormatting
private static sbyte GetRunBidiLevel(DrawableTextRun run, FlowDirection flowDirection) private static sbyte GetRunBidiLevel(DrawableTextRun run, FlowDirection flowDirection)
{ {
if (run is ShapedTextCharacters shapedTextCharacters) if (run is ShapedTextRun shapedTextCharacters)
{ {
return shapedTextCharacters.BidiLevel; return shapedTextCharacters.BidiLevel;
} }
@ -1027,7 +1027,7 @@ namespace Avalonia.Media.TextFormatting
{ {
if (current.Level >= minLevelToReverse && current.Level % 2 != 0) if (current.Level >= minLevelToReverse && current.Level % 2 != 0)
{ {
if (current.Run is ShapedTextCharacters { IsReversed: false } shapedTextCharacters) if (current.Run is ShapedTextRun { IsReversed: false } shapedTextCharacters)
{ {
shapedTextCharacters.Reverse(); shapedTextCharacters.Reverse();
} }
@ -1145,7 +1145,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _); var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);
@ -1230,7 +1230,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _); var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
@ -1294,7 +1294,7 @@ namespace Avalonia.Media.TextFormatting
switch (currentRun) switch (currentRun)
{ {
case ShapedTextCharacters shapedRun: case ShapedTextRun shapedRun:
{ {
var firstCluster = shapedRun.GlyphRun.Metrics.FirstCluster; var firstCluster = shapedRun.GlyphRun.Metrics.FirstCluster;
@ -1303,7 +1303,7 @@ namespace Avalonia.Media.TextFormatting
break; break;
} }
if (previousRun is ShapedTextCharacters previousShaped && !previousShaped.ShapedBuffer.IsLeftToRight) if (previousRun is ShapedTextRun previousShaped && !previousShaped.ShapedBuffer.IsLeftToRight)
{ {
if (shapedRun.ShapedBuffer.IsLeftToRight) if (shapedRun.ShapedBuffer.IsLeftToRight)
{ {
@ -1394,7 +1394,7 @@ namespace Avalonia.Media.TextFormatting
{ {
switch (_textRuns[index]) switch (_textRuns[index])
{ {
case ShapedTextCharacters textRun: case ShapedTextRun textRun:
{ {
var textMetrics = var textMetrics =
new TextMetrics(textRun.Properties.Typeface.GlyphTypeface, textRun.Properties.FontRenderingEmSize); new TextMetrics(textRun.Properties.Typeface.GlyphTypeface, textRun.Properties.FontRenderingEmSize);

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

@ -44,7 +44,7 @@ namespace Avalonia.Media.TextFormatting
fixed (char* charsPtr = characterBuffer.Span) fixed (char* charsPtr = characterBuffer.Span)
{ {
return new string(charsPtr, 0, characterBuffer.Span.Length); return new string(charsPtr, _textRun.CharacterBufferReference.OffsetToFirstChar, _textRun.Length);
} }
} }
} }

16
src/Avalonia.Base/Media/TextFormatting/ShapeableTextCharacters.cs → src/Avalonia.Base/Media/TextFormatting/UnshapedTextRun.cs

@ -5,9 +5,9 @@ namespace Avalonia.Media.TextFormatting
/// <summary> /// <summary>
/// A group of characters that can be shaped. /// A group of characters that can be shaped.
/// </summary> /// </summary>
public sealed class ShapeableTextCharacters : TextRun public sealed class UnshapedTextRun : TextRun
{ {
public ShapeableTextCharacters(CharacterBufferReference characterBufferReference, int length, public UnshapedTextRun(CharacterBufferReference characterBufferReference, int length,
TextRunProperties properties, sbyte biDiLevel) TextRunProperties properties, sbyte biDiLevel)
{ {
CharacterBufferReference = characterBufferReference; CharacterBufferReference = characterBufferReference;
@ -24,30 +24,30 @@ namespace Avalonia.Media.TextFormatting
public sbyte BidiLevel { get; } public sbyte BidiLevel { get; }
public bool CanShapeTogether(ShapeableTextCharacters shapeableTextCharacters) public bool CanShapeTogether(UnshapedTextRun unshapedTextRun)
{ {
if (!CharacterBufferReference.Equals(shapeableTextCharacters.CharacterBufferReference)) if (!CharacterBufferReference.Equals(unshapedTextRun.CharacterBufferReference))
{ {
return false; return false;
} }
if (BidiLevel != shapeableTextCharacters.BidiLevel) if (BidiLevel != unshapedTextRun.BidiLevel)
{ {
return false; return false;
} }
if (!MathUtilities.AreClose(Properties.FontRenderingEmSize, if (!MathUtilities.AreClose(Properties.FontRenderingEmSize,
shapeableTextCharacters.Properties.FontRenderingEmSize)) unshapedTextRun.Properties.FontRenderingEmSize))
{ {
return false; return false;
} }
if (Properties.Typeface != shapeableTextCharacters.Properties.Typeface) if (Properties.Typeface != unshapedTextRun.Properties.Typeface)
{ {
return false; return false;
} }
if (Properties.BaselineAlignment != shapeableTextCharacters.Properties.BaselineAlignment) if (Properties.BaselineAlignment != unshapedTextRun.Properties.BaselineAlignment)
{ {
return false; return false;
} }

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

@ -111,7 +111,7 @@ namespace Avalonia.Rendering.Composition
} }
} }
batch.CommitedAt = Server.Clock.Elapsed; batch.CommittedAt = Server.Clock.Elapsed;
_server.EnqueueBatch(batch); _server.EnqueueBatch(batch);
lock (_pendingBatchLock) lock (_pendingBatchLock)

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

@ -48,7 +48,7 @@ internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisua
} }
} }
protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt) protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt)
{ {
if (reader.Read<byte>() == 1) if (reader.Read<byte>() == 1)
{ {
@ -56,7 +56,7 @@ internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisua
_renderCommands = reader.ReadObject<CompositionDrawList?>(); _renderCommands = reader.ReadObject<CompositionDrawList?>();
_contentBounds = null; _contentBounds = null;
} }
base.DeserializeChangesCore(reader, commitedAt); base.DeserializeChangesCore(reader, committedAt);
} }
protected override void RenderCore(CompositorDrawingContextProxy canvas, Rect currentTransformedClip) protected override void RenderCore(CompositorDrawingContextProxy canvas, Rect currentTransformedClip)

6
src/Avalonia.Base/Rendering/Composition/Server/ServerCustomCompositionVisual.cs

@ -16,9 +16,9 @@ internal class ServerCompositionCustomVisual : ServerCompositionContainerVisual,
_handler.Attach(this); _handler.Attach(this);
} }
protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt) protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt)
{ {
base.DeserializeChangesCore(reader, commitedAt); base.DeserializeChangesCore(reader, committedAt);
var count = reader.Read<int>(); var count = reader.Read<int>();
for (var c = 0; c < count; c++) for (var c = 0; c < count; c++)
{ {
@ -79,4 +79,4 @@ internal class ServerCompositionCustomVisual : ServerCompositionContainerVisual,
?.Log(_handler, $"Exception in {_handler.GetType().Name}.{nameof(CompositionCustomVisualHandler.OnRender)} {{0}}", e); ?.Log(_handler, $"Exception in {_handler.GetType().Name}.{nameof(CompositionCustomVisualHandler.OnRender)} {{0}}", e);
} }
} }
} }

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

@ -14,7 +14,7 @@ namespace Avalonia.Rendering.Composition.Server
{ {
public List<T> List { get; } = new List<T>(); public List<T> List { get; } = new List<T>();
protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt) protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt)
{ {
if (reader.Read<byte>() == 1) if (reader.Read<byte>() == 1)
{ {
@ -23,7 +23,7 @@ namespace Avalonia.Rendering.Composition.Server
for (var c = 0; c < count; c++) for (var c = 0; c < count; c++)
List.Add(reader.ReadObject<T>()); List.Add(reader.ReadObject<T>());
} }
base.DeserializeChangesCore(reader, commitedAt); base.DeserializeChangesCore(reader, committedAt);
} }
public override long LastChangedBy public override long LastChangedBy

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

@ -104,13 +104,13 @@ namespace Avalonia.Rendering.Composition.Server
} }
protected void SetAnimatedValue<T>(CompositionProperty prop, ref T field, protected void SetAnimatedValue<T>(CompositionProperty prop, ref T field,
TimeSpan commitedAt, IAnimationInstance animation) where T : struct TimeSpan committedAt, IAnimationInstance animation) where T : struct
{ {
if (IsActive && _animations.TryGetValue(prop, out var oldAnimation)) if (IsActive && _animations.TryGetValue(prop, out var oldAnimation))
oldAnimation.Deactivate(); oldAnimation.Deactivate();
_animations[prop] = animation; _animations[prop] = animation;
animation.Initialize(commitedAt, ExpressionVariant.Create(field), prop); animation.Initialize(committedAt, ExpressionVariant.Create(field), prop);
if(IsActive) if(IsActive)
animation.Activate(); animation.Activate();
@ -165,7 +165,7 @@ namespace Avalonia.Rendering.Composition.Server
public virtual CompositionProperty? GetCompositionProperty(string fieldName) => null; public virtual CompositionProperty? GetCompositionProperty(string fieldName) => null;
protected virtual void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt) protected virtual void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt)
{ {
if (this is IDisposable disp if (this is IDisposable disp
&& reader.Read<byte>() == 1) && reader.Read<byte>() == 1)
@ -174,7 +174,7 @@ namespace Avalonia.Rendering.Composition.Server
public void DeserializeChanges(BatchStreamReader reader, Batch batch) public void DeserializeChanges(BatchStreamReader reader, Batch batch)
{ {
DeserializeChangesCore(reader, batch.CommitedAt); DeserializeChangesCore(reader, batch.CommittedAt);
ValuesInvalidated(); ValuesInvalidated();
ItselfLastChangedBy = batch.SequenceId; ItselfLastChangedBy = batch.SequenceId;
} }

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

@ -29,7 +29,7 @@ namespace Avalonia.Rendering.Composition.Transport
public BatchStreamData Changes { get; private set; } public BatchStreamData Changes { get; private set; }
public TimeSpan CommitedAt { get; set; } public TimeSpan CommittedAt { get; set; }
public void Complete() public void Complete()
{ {

1
src/Avalonia.Base/Visual.cs

@ -480,6 +480,7 @@ namespace Avalonia
{ {
AttachToCompositor(compositingRenderer.Compositor); AttachToCompositor(compositingRenderer.Compositor);
} }
InvalidateMirrorTransform();
OnAttachedToVisualTree(e); OnAttachedToVisualTree(e);
AttachedToVisualTree?.Invoke(this, e); AttachedToVisualTree?.Invoke(this, e);
InvalidateVisual(); InvalidateVisual();

4
src/Avalonia.Build.Tasks/ComInteropHelper.cs

@ -65,10 +65,8 @@ namespace Avalonia.Build.Tasks
{ {
Instruction instruction = instructions[i]; Instruction instruction = instructions[i];
if (instruction.OpCode == OpCodes.Call && instruction.Operand is MethodReference) if (instruction.OpCode == OpCodes.Call && instruction.Operand is MethodReference methodDescription)
{ {
var methodDescription = (MethodReference)instruction.Operand;
if (methodDescription.Name.StartsWith("Calli") && methodDescription.DeclaringType.Name == "LocalInterop") if (methodDescription.Name.StartsWith("Calli") && methodDescription.DeclaringType.Name == "LocalInterop")
{ {
var callSite = new CallSite(methodDescription.ReturnType) { CallingConvention = MethodCallingConvention.StdCall }; var callSite = new CallSite(methodDescription.ReturnType) { CallingConvention = MethodCallingConvention.StdCall };

4
src/Avalonia.Controls.ColorPicker/ColorPalettes/FlatColorPalette.cs

@ -289,8 +289,8 @@ namespace Avalonia.Controls
}; };
// See: https://htmlcolorcodes.com/assets/downloads/flat-design-colors/flat-design-color-chart.png // See: https://htmlcolorcodes.com/assets/downloads/flat-design-colors/flat-design-color-chart.png
protected static Color[,]? _colorChart = null; private static Color[,]? _colorChart = null;
protected static object _colorChartMutex = new object(); private static readonly object _colorChartMutex = new();
/// <summary> /// <summary>
/// Initializes all color chart colors. /// Initializes all color chart colors.

4
src/Avalonia.Controls.ColorPicker/ColorPalettes/FlatHalfColorPalette.cs

@ -10,8 +10,8 @@ namespace Avalonia.Controls
/// <inheritdoc cref="FlatColorPalette"/> /// <inheritdoc cref="FlatColorPalette"/>
public class FlatHalfColorPalette : IColorPalette public class FlatHalfColorPalette : IColorPalette
{ {
protected static Color[,]? _colorChart = null; private static Color[,]? _colorChart = null;
protected static object _colorChartMutex = new object(); private static readonly object _colorChartMutex = new();
/// <summary> /// <summary>
/// Initializes all color chart colors. /// Initializes all color chart colors.

4
src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs

@ -344,8 +344,8 @@ namespace Avalonia.Controls
// See: https://material.io/design/color/the-color-system.html#tools-for-picking-colors // See: https://material.io/design/color/the-color-system.html#tools-for-picking-colors
// This is a reduced palette for uniformity // This is a reduced palette for uniformity
protected static Color[,]? _colorChart = null; private static Color[,]? _colorChart = null;
protected static object _colorChartMutex = new object(); private static readonly object _colorChartMutex = new();
/// <summary> /// <summary>
/// Initializes all color chart colors. /// Initializes all color chart colors.

4
src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialHalfColorPalette.cs

@ -10,8 +10,8 @@ namespace Avalonia.Controls
/// <inheritdoc cref="MaterialColorPalette"/> /// <inheritdoc cref="MaterialColorPalette"/>
public class MaterialHalfColorPalette : IColorPalette public class MaterialHalfColorPalette : IColorPalette
{ {
protected static Color[,]? _colorChart = null; private static Color[,]? _colorChart = null;
protected static object _colorChartMutex = new object(); private static readonly object _colorChartMutex = new();
/// <summary> /// <summary>
/// Initializes all color chart colors. /// Initializes all color chart colors.

2
src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs

@ -31,7 +31,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="IsThreeState"/> property. /// Defines the <see cref="IsThreeState"/> property.
/// </summary> /// </summary>
public static StyledProperty<bool> IsThreeStateProperty = public static readonly StyledProperty<bool> IsThreeStateProperty =
CheckBox.IsThreeStateProperty.AddOwner<DataGridCheckBoxColumn>(); CheckBox.IsThreeStateProperty.AddOwner<DataGridCheckBoxColumn>();
/// <summary> /// <summary>

2
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@ -185,7 +185,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="IsVisible"/> property. /// Defines the <see cref="IsVisible"/> property.
/// </summary> /// </summary>
public static StyledProperty<bool> IsVisibleProperty = public static readonly StyledProperty<bool> IsVisibleProperty =
Control.IsVisibleProperty.AddOwner<DataGridColumn>(); Control.IsVisibleProperty.AddOwner<DataGridColumn>();
/// <summary> /// <summary>

1
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -474,6 +474,7 @@ namespace Avalonia.Controls
FilterModeProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnFilterModePropertyChanged(e)); FilterModeProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnFilterModePropertyChanged(e));
ItemFilterProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemFilterPropertyChanged(e)); ItemFilterProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemFilterPropertyChanged(e));
ItemsProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemsPropertyChanged(e)); ItemsProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemsPropertyChanged(e));
ItemTemplateProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemTemplatePropertyChanged(e));
IsEnabledProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnControlIsEnabledChanged(e)); IsEnabledProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnControlIsEnabledChanged(e));
} }

4
src/Avalonia.Controls/BorderVisual.cs

@ -63,9 +63,9 @@ class CompositionBorderVisual : CompositionDrawListVisual
} }
protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt) protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt)
{ {
base.DeserializeChangesCore(reader, commitedAt); base.DeserializeChangesCore(reader, committedAt);
if (reader.Read<bool>()) if (reader.Read<bool>())
_cornerRadius = reader.Read<CornerRadius>(); _cornerRadius = reader.Read<CornerRadius>();
} }

8
src/Avalonia.Controls/Control.cs

@ -392,14 +392,6 @@ namespace Avalonia.Controls
OnUnloadedCore(); OnUnloadedCore();
} }
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
InvalidateMirrorTransform();
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnGotFocus(GotFocusEventArgs e) protected override void OnGotFocus(GotFocusEventArgs e)
{ {

2
src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs

@ -8,6 +8,6 @@
/// <summary> /// <summary>
/// Provides access to the internal <see cref="ToolTip.ToolTipProperty"/> for use in DevTools. /// Provides access to the internal <see cref="ToolTip.ToolTipProperty"/> for use in DevTools.
/// </summary> /// </summary>
public static AvaloniaProperty<ToolTip?> ToolTipProperty = ToolTip.ToolTipProperty; public static readonly AvaloniaProperty<ToolTip?> ToolTipProperty = ToolTip.ToolTipProperty;
} }
} }

1
src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs

@ -94,6 +94,7 @@ namespace Avalonia.Controls.Presenters
{ {
AddHandler(RequestBringIntoViewEvent, BringIntoViewRequested); AddHandler(RequestBringIntoViewEvent, BringIntoViewRequested);
AddHandler(Gestures.ScrollGestureEvent, OnScrollGesture); AddHandler(Gestures.ScrollGestureEvent, OnScrollGesture);
AddHandler(Gestures.ScrollGestureEndedEvent, OnScrollGestureEnded);
this.GetObservable(ChildProperty).Subscribe(UpdateScrollableSubscription); this.GetObservable(ChildProperty).Subscribe(UpdateScrollableSubscription);
} }

4
src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs

@ -197,12 +197,12 @@ namespace Avalonia.Controls.PullToRefresh
throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content property must be a Visual"); throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content property must be a Visual");
} }
if (content.Parent is not InputElement) if (content.Parent is not InputElement parent)
{ {
throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content parent must be an InputElement"); throw new ArgumentException(nameof(_scrollViewer), "Adaptee's content parent must be an InputElement");
} }
MakeInteractionSource(content.Parent as InputElement); MakeInteractionSource(parent);
if (_scrollViewer != null) if (_scrollViewer != null)
{ {

4
src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs

@ -59,7 +59,7 @@ namespace Avalonia.Controls.Templates
/// <returns>The untyped function.</returns> /// <returns>The untyped function.</returns>
private static Func<object?, bool> CastMatch(Func<T, bool> f) private static Func<object?, bool> CastMatch(Func<T, bool> f)
{ {
return o => (o is T) && f((T)o); return o => o is T arg && f(arg);
} }
/// <summary> /// <summary>
@ -72,7 +72,7 @@ namespace Avalonia.Controls.Templates
{ {
return (o, s) => f((T)o!, s); return (o, s) => f((T)o!, s);
} }
/// <summary> /// <summary>
/// Casts a function with a typed parameter to an untyped function. /// Casts a function with a typed parameter to an untyped function.
/// </summary> /// </summary>

6
src/Avalonia.Controls/TransitioningContentControl.cs

@ -69,6 +69,10 @@ public class TransitioningContentControl : ContentControl
{ {
Dispatcher.UIThread.Post(() => UpdateContentWithTransition(Content)); Dispatcher.UIThread.Post(() => UpdateContentWithTransition(Content));
} }
else if (change.Property == CurrentContentProperty)
{
UpdateLogicalTree(change.OldValue, change.NewValue);
}
} }
protected override void ContentChanged(AvaloniaPropertyChangedEventArgs e) protected override void ContentChanged(AvaloniaPropertyChangedEventArgs e)
@ -94,8 +98,6 @@ public class TransitioningContentControl : ContentControl
if (PageTransition != null) if (PageTransition != null)
await PageTransition.Start(this, null, true, localToken); await PageTransition.Start(this, null, true, localToken);
UpdateLogicalTree(CurrentContent, content);
if (localToken.IsCancellationRequested) if (localToken.IsCancellationRequested)
{ {
return; return;

8
src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs

@ -33,12 +33,12 @@ namespace Avalonia.Diagnostics.ViewModels
{ {
_avaloniaObject = avaloniaObject; _avaloniaObject = avaloniaObject;
TreePage = treePage; TreePage = treePage;
Layout = avaloniaObject is Visual Layout = avaloniaObject is Visual visual
? new ControlLayoutViewModel((Visual)avaloniaObject) ? new ControlLayoutViewModel(visual)
: default; : default;
NavigateToProperty(_avaloniaObject, (_avaloniaObject as Control)?.Name ?? _avaloniaObject.ToString()); NavigateToProperty(_avaloniaObject, (_avaloniaObject as Control)?.Name ?? _avaloniaObject.ToString());
AppliedStyles = new ObservableCollection<StyleViewModel>(); AppliedStyles = new ObservableCollection<StyleViewModel>();
PseudoClasses = new ObservableCollection<PseudoClassViewModel>(); PseudoClasses = new ObservableCollection<PseudoClassViewModel>();

1
src/Browser/Avalonia.Browser.Blazor/Avalonia.Browser.Blazor.csproj

@ -7,6 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<SupportedPlatform Remove="@(SupportedPlatform)" />
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>

3
src/Browser/Avalonia.Browser.Blazor/AvaloniaView.cs

@ -8,9 +8,10 @@ using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering; using Microsoft.AspNetCore.Components.Rendering;
using BrowserView = Avalonia.Browser.AvaloniaView; using BrowserView = Avalonia.Browser.AvaloniaView;
[assembly: SupportedOSPlatform("browser")]
namespace Avalonia.Browser.Blazor; namespace Avalonia.Browser.Blazor;
[SupportedOSPlatform("browser")]
public class AvaloniaView : ComponentBase public class AvaloniaView : ComponentBase
{ {
private Browser.AvaloniaView? _browserView; private Browser.AvaloniaView? _browserView;

1
src/Browser/Avalonia.Browser.Blazor/BlazorSingleViewLifetime.cs

@ -5,7 +5,6 @@ using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.Browser.Blazor; namespace Avalonia.Browser.Blazor;
[SupportedOSPlatform("browser")]
public static class WebAppBuilder public static class WebAppBuilder
{ {
public static AppBuilder SetupWithSingleViewLifetime( public static AppBuilder SetupWithSingleViewLifetime(

1
src/Browser/Avalonia.Browser/AvaloniaView.cs

@ -18,7 +18,6 @@ using SkiaSharp;
namespace Avalonia.Browser namespace Avalonia.Browser
{ {
[System.Runtime.Versioning.SupportedOSPlatform("browser")] // gets rid of callsite warnings
public partial class AvaloniaView : ITextInputMethodImpl public partial class AvaloniaView : ITextInputMethodImpl
{ {
private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new(ClearMode.Never); private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new(ClearMode.Never);

2
src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs

@ -5,7 +5,6 @@ using System.Runtime.Versioning;
namespace Avalonia.Browser; namespace Avalonia.Browser;
[SupportedOSPlatform("browser")]
public class BrowserSingleViewLifetime : ISingleViewApplicationLifetime public class BrowserSingleViewLifetime : ISingleViewApplicationLifetime
{ {
public AvaloniaView? View; public AvaloniaView? View;
@ -22,7 +21,6 @@ public class BrowserPlatformOptions
public Func<string, string> FrameworkAssetPathResolver { get; set; } = new(fileName => $"./{fileName}"); public Func<string, string> FrameworkAssetPathResolver { get; set; } = new(fileName => $"./{fileName}");
} }
[SupportedOSPlatform("browser")]
public static class WebAppBuilder public static class WebAppBuilder
{ {
public static AppBuilder SetupBrowserApp( public static AppBuilder SetupBrowserApp(

12
src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.Versioning;
using Avalonia.Browser.Skia; using Avalonia.Browser.Skia;
using Avalonia.Browser.Storage; using Avalonia.Browser.Storage;
using Avalonia.Controls; using Avalonia.Controls;
@ -14,9 +15,10 @@ using Avalonia.Platform.Storage;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
[assembly: SupportedOSPlatform("browser")]
namespace Avalonia.Browser namespace Avalonia.Browser
{ {
[System.Runtime.Versioning.SupportedOSPlatform("browser")] // gets rid of callsite warnings
internal class BrowserTopLevelImpl : ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider internal class BrowserTopLevelImpl : ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider
{ {
private Size _clientSize; private Size _clientSize;
@ -201,7 +203,11 @@ namespace Avalonia.Browser
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{ {
if (transparencyLevel == WindowTransparencyLevel.None
|| transparencyLevel == WindowTransparencyLevel.Transparent)
{
TransparencyLevel = transparencyLevel;
}
} }
public Size ClientSize => _clientSize; public Size ClientSize => _clientSize;
@ -221,7 +227,7 @@ namespace Avalonia.Browser
public IMouseDevice MouseDevice { get; } = new MouseDevice(); public IMouseDevice MouseDevice { get; } = new MouseDevice();
public IKeyboardDevice KeyboardDevice { get; } = BrowserWindowingPlatform.Keyboard; public IKeyboardDevice KeyboardDevice { get; } = BrowserWindowingPlatform.Keyboard;
public WindowTransparencyLevel TransparencyLevel { get; } public WindowTransparencyLevel TransparencyLevel { get; private set; }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; }
public ITextInputMethodImpl TextInputMethod => _avaloniaView; public ITextInputMethodImpl TextInputMethod => _avaloniaView;

1
src/Browser/Avalonia.Browser/Interop/CanvasHelper.cs

@ -6,7 +6,6 @@ namespace Avalonia.Browser.Interop;
internal record GLInfo(int ContextId, uint FboId, int Stencils, int Samples, int Depth); internal record GLInfo(int ContextId, uint FboId, int Stencils, int Samples, int Depth);
[System.Runtime.Versioning.SupportedOSPlatform("browser")] // gets rid of callsite warnings
internal static partial class CanvasHelper internal static partial class CanvasHelper
{ {

14
src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpuRenderTarget.cs

@ -14,14 +14,12 @@ namespace Avalonia.Browser.Skia
_size = browserSkiaSurface.Size; _size = browserSkiaSurface.Size;
var glFbInfo = new GRGlFramebufferInfo(browserSkiaSurface.GlInfo.FboId, browserSkiaSurface.ColorType.ToGlSizedFormat()); var glFbInfo = new GRGlFramebufferInfo(browserSkiaSurface.GlInfo.FboId, browserSkiaSurface.ColorType.ToGlSizedFormat());
{ _browserSkiaSurface = browserSkiaSurface;
_browserSkiaSurface = browserSkiaSurface; _renderTarget = new GRBackendRenderTarget(
_renderTarget = new GRBackendRenderTarget( (int)(browserSkiaSurface.Size.Width * browserSkiaSurface.Scaling),
(int)(browserSkiaSurface.Size.Width * browserSkiaSurface.Scaling), (int)(browserSkiaSurface.Size.Height * browserSkiaSurface.Scaling),
(int)(browserSkiaSurface.Size.Height * browserSkiaSurface.Scaling), browserSkiaSurface.GlInfo.Samples,
browserSkiaSurface.GlInfo.Samples, browserSkiaSurface.GlInfo.Stencils, glFbInfo);
browserSkiaSurface.GlInfo.Stencils, glFbInfo);
}
} }
public void Dispose() public void Dispose()

1
src/Browser/Avalonia.Browser/Storage/BlobReadableStream.cs

@ -7,7 +7,6 @@ using Avalonia.Browser.Interop;
namespace Avalonia.Browser.Storage; namespace Avalonia.Browser.Storage;
[System.Runtime.Versioning.SupportedOSPlatform("browser")]
internal class BlobReadableStream : Stream internal class BlobReadableStream : Stream
{ {
private JSObject? _jSReference; private JSObject? _jSReference;

1
src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs

@ -13,7 +13,6 @@ namespace Avalonia.Browser.Storage;
internal record FilePickerAcceptType(string Description, IReadOnlyDictionary<string, IReadOnlyList<string>> Accept); internal record FilePickerAcceptType(string Description, IReadOnlyDictionary<string, IReadOnlyList<string>> Accept);
[SupportedOSPlatform("browser")]
internal class BrowserStorageProvider : IStorageProvider internal class BrowserStorageProvider : IStorageProvider
{ {
internal const string PickerCancelMessage = "The user aborted a request"; internal const string PickerCancelMessage = "The user aborted a request";

1
src/Browser/Avalonia.Browser/Storage/WriteableStream.cs

@ -7,7 +7,6 @@ using Avalonia.Browser.Interop;
namespace Avalonia.Browser.Storage; namespace Avalonia.Browser.Storage;
[System.Runtime.Versioning.SupportedOSPlatform("browser")]
// Loose wrapper implementaion of a stream on top of FileAPI FileSystemWritableFileStream // Loose wrapper implementaion of a stream on top of FileAPI FileSystemWritableFileStream
internal sealed class WriteableStream : Stream internal sealed class WriteableStream : Stream
{ {

1
src/Browser/Avalonia.Browser/webapp/modules/avalonia/dom.ts

@ -17,7 +17,6 @@ export class AvaloniaDOM {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
canvas.id = `canvas${randomIdPart}`; canvas.id = `canvas${randomIdPart}`;
canvas.classList.add("avalonia-canvas"); canvas.classList.add("avalonia-canvas");
canvas.style.backgroundColor = "#ccc";
canvas.style.width = "100%"; canvas.style.width = "100%";
canvas.style.position = "absolute"; canvas.style.position = "absolute";

2
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@ -179,7 +179,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
} }
finally finally
{ {
if( _sreCanSave) if(!success && _sreCanSave)
DumpRuntimeCompilationResults(); DumpRuntimeCompilationResults();
} }
} }

12
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs

@ -552,7 +552,8 @@ namespace Avalonia.Markup.Parsers
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return obj is ClassSyntax && ((ClassSyntax)obj).Class == Class; return obj is ClassSyntax syntax &&
syntax.Class == Class;
} }
} }
@ -562,7 +563,8 @@ namespace Avalonia.Markup.Parsers
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return obj is NameSyntax && ((NameSyntax)obj).Name == Name; return obj is NameSyntax syntax &&
syntax.Name == Name;
} }
} }
@ -574,9 +576,9 @@ namespace Avalonia.Markup.Parsers
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return obj is PropertySyntax && return obj is PropertySyntax syntax &&
((PropertySyntax)obj).Property == Property && syntax.Property == Property &&
((PropertySyntax)obj).Value == Value; syntax.Value == Value;
} }
} }

2
src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs

@ -28,7 +28,7 @@ namespace Avalonia.Win32.Interop.Wpf
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(null, obj)) return false;
return obj is IntSize && Equals((IntSize) obj); return obj is IntSize size && Equals(size);
} }
public override int GetHashCode() public override int GetHashCode()

2
src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs

@ -109,7 +109,7 @@ namespace Avalonia.Win32
if (_owner is Window window) if (_owner is Window window)
{ {
var visual = window.Renderer.HitTestFirst(position, (Visual)_owner, x => var visual = window.Renderer.HitTestFirst(position, window, x =>
{ {
if (x is IInputElement ie && (!ie.IsHitTestVisible || !ie.IsEffectivelyVisible)) if (x is IInputElement ie && (!ie.IsHitTestVisible || !ie.IsEffectivelyVisible))
{ {

2
src/tools/DevAnalyzers/GenericVirtualAnalyzer.cs

@ -16,7 +16,7 @@ public class GenericVirtualAnalyzer : DiagnosticAnalyzer
"Performance", "Performance",
DiagnosticSeverity.Warning, DiagnosticSeverity.Warning,
isEnabledByDefault: true, isEnabledByDefault: true,
description: "Generic virtual methods affect JIT startup time adversly and should be avoided."); description: "Generic virtual methods affect JIT startup time adversely and should be avoided.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

6
src/tools/DevGenerators/CompositionGenerator/Generator.cs

@ -257,7 +257,7 @@ namespace Avalonia.SourceGenerator.CompositionGenerator
if (cl.Properties.Count > 0) if (cl.Properties.Count > 0)
{ {
server = server.AddMembers(((MethodDeclarationSyntax)ParseMemberDeclaration( server = server.AddMembers(((MethodDeclarationSyntax)ParseMemberDeclaration(
$"protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt){{}}") $"protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt){{}}")
!) !)
.WithBody(ApplyDeserializeChangesEpilogue(deserializeMethodBody, cl))); .WithBody(ApplyDeserializeChangesEpilogue(deserializeMethodBody, cl)));
server = server.AddMembers(MethodDeclaration(ParseTypeName("void"), "OnFieldsDeserialized") server = server.AddMembers(MethodDeclaration(ParseTypeName("void"), "OnFieldsDeserialized")
@ -481,7 +481,7 @@ return;
private static BlockSyntax DeserializeChangesPrologue(GClass cl) private static BlockSyntax DeserializeChangesPrologue(GClass cl)
{ {
return Block(ParseStatement($@" return Block(ParseStatement($@"
base.DeserializeChangesCore(reader, commitedAt); base.DeserializeChangesCore(reader, committedAt);
DeserializeChangesExtra(reader); DeserializeChangesExtra(reader);
var changed = reader.Read<{ChangedFieldsTypeName(cl)}>(); var changed = reader.Read<{ChangedFieldsTypeName(cl)}>();
")); "));
@ -500,7 +500,7 @@ var changed = reader.Read<{ChangedFieldsTypeName(cl)}>();
{ {
code = $@" code = $@"
if((changed & {changedFieldsType}.{prop.Name}Animated) == {changedFieldsType}.{prop.Name}Animated) if((changed & {changedFieldsType}.{prop.Name}Animated) == {changedFieldsType}.{prop.Name}Animated)
SetAnimatedValue({CompositionPropertyField(prop)}, ref {PropertyBackingFieldName(prop)}, commitedAt, reader.ReadObject<IAnimationInstance>()); SetAnimatedValue({CompositionPropertyField(prop)}, ref {PropertyBackingFieldName(prop)}, committedAt, reader.ReadObject<IAnimationInstance>());
else "; else ";
} }

4
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

@ -520,7 +520,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var expectedTextLine = formatter.FormatLine(new SingleBufferTextSource(text, defaultProperties), var expectedTextLine = formatter.FormatLine(new SingleBufferTextSource(text, defaultProperties),
0, double.PositiveInfinity, paragraphProperties); 0, double.PositiveInfinity, paragraphProperties);
var expectedRuns = expectedTextLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var expectedRuns = expectedTextLine.TextRuns.Cast<ShapedTextRun>().ToList();
var expectedGlyphs = expectedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList(); var expectedGlyphs = expectedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList();
@ -539,7 +539,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties); formatter.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
var shapedRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var shapedRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var actualGlyphs = shapedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList(); var actualGlyphs = shapedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList();

28
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs

@ -141,7 +141,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
black, black,
textWrapping: TextWrapping.Wrap); textWrapping: TextWrapping.Wrap);
var expectedGlyphs = expected.TextLines.Select(x => string.Join('|', x.TextRuns.Cast<ShapedTextCharacters>() var expectedGlyphs = expected.TextLines.Select(x => string.Join('|', x.TextRuns.Cast<ShapedTextRun>()
.SelectMany(x => x.ShapedBuffer.GlyphIndices))).ToList(); .SelectMany(x => x.ShapedBuffer.GlyphIndices))).ToList();
var outer = new GraphemeEnumerator(new CharacterBufferRange(text)); var outer = new GraphemeEnumerator(new CharacterBufferRange(text));
@ -174,7 +174,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
textWrapping: TextWrapping.Wrap, textWrapping: TextWrapping.Wrap,
textStyleOverrides: spans); textStyleOverrides: spans);
var actualGlyphs = actual.TextLines.Select(x => string.Join('|', x.TextRuns.Cast<ShapedTextCharacters>() var actualGlyphs = actual.TextLines.Select(x => string.Join('|', x.TextRuns.Cast<ShapedTextRun>()
.SelectMany(x => x.ShapedBuffer.GlyphIndices))).ToList(); .SelectMany(x => x.ShapedBuffer.GlyphIndices))).ToList();
Assert.Equal(expectedGlyphs.Count, actualGlyphs.Count); Assert.Equal(expectedGlyphs.Count, actualGlyphs.Count);
@ -447,7 +447,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
12.0f, 12.0f,
Brushes.Black.ToImmutable()); Brushes.Black.ToImmutable());
var shapedRun = (ShapedTextCharacters)layout.TextLines[0].TextRuns[0]; var shapedRun = (ShapedTextRun)layout.TextLines[0].TextRuns[0];
var glyphRun = shapedRun.GlyphRun; var glyphRun = shapedRun.GlyphRun;
@ -481,7 +481,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
foreach (var textRun in textLine.TextRuns) foreach (var textRun in textLine.TextRuns)
{ {
var shapedRun = (ShapedTextCharacters)textRun; var shapedRun = (ShapedTextRun)textRun;
var glyphClusters = shapedRun.ShapedBuffer.GlyphClusters; var glyphClusters = shapedRun.ShapedBuffer.GlyphClusters;
@ -514,13 +514,13 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
Assert.Equal(1, layout.TextLines[0].TextRuns.Count); Assert.Equal(1, layout.TextLines[0].TextRuns.Count);
Assert.Equal(expectedLength, ((ShapedTextCharacters)layout.TextLines[0].TextRuns[0]).GlyphRun.GlyphClusters.Count); Assert.Equal(expectedLength, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).GlyphRun.GlyphClusters.Count);
Assert.Equal(5, ((ShapedTextCharacters)layout.TextLines[0].TextRuns[0]).ShapedBuffer.GlyphClusters[5]); Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).ShapedBuffer.GlyphClusters[5]);
if (expectedLength == 7) if (expectedLength == 7)
{ {
Assert.Equal(5, ((ShapedTextCharacters)layout.TextLines[0].TextRuns[0]).ShapedBuffer.GlyphClusters[6]); Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).ShapedBuffer.GlyphClusters[6]);
} }
} }
} }
@ -555,7 +555,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = layout.TextLines[0]; var textLine = layout.TextLines[0];
var textRun = (ShapedTextCharacters)textLine.TextRuns[0]; var textRun = (ShapedTextRun)textLine.TextRuns[0];
Assert.Equal(7, textRun.Length); Assert.Equal(7, textRun.Length);
@ -775,7 +775,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
Assert.Equal(textLine.WidthIncludingTrailingWhitespace, rect.Width); Assert.Equal(textLine.WidthIncludingTrailingWhitespace, rect.Width);
} }
var rects = layout.TextLines.SelectMany(x => x.TextRuns.Cast<ShapedTextCharacters>()) var rects = layout.TextLines.SelectMany(x => x.TextRuns.Cast<ShapedTextRun>())
.SelectMany(x => x.ShapedBuffer.GlyphAdvances).ToArray(); .SelectMany(x => x.ShapedBuffer.GlyphAdvances).ToArray();
for (var i = 0; i < SingleLineText.Length; i++) for (var i = 0; i < SingleLineText.Length; i++)
@ -814,7 +814,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
Assert.True(textLine.Width <= maxWidth); Assert.True(textLine.Width <= maxWidth);
var actual = new string(textLine.TextRuns.Cast<ShapedTextCharacters>() var actual = new string(textLine.TextRuns.Cast<ShapedTextRun>()
.OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar) .OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar)
.SelectMany(x => new CharacterBufferRange(x.CharacterBufferReference, x.Length)).ToArray()); .SelectMany(x => new CharacterBufferRange(x.CharacterBufferReference, x.Length)).ToArray());
@ -855,7 +855,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
Brushes.Black, Brushes.Black,
flowDirection: FlowDirection.RightToLeft); flowDirection: FlowDirection.RightToLeft);
var firstRun = layout.TextLines[0].TextRuns[0] as ShapedTextCharacters; var firstRun = layout.TextLines[0].TextRuns[0] as ShapedTextRun;
var hit = layout.HitTestPoint(new Point()); var hit = layout.HitTestPoint(new Point());
@ -881,7 +881,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
currentX += advance; currentX += advance;
} }
var secondRun = layout.TextLines[0].TextRuns[1] as ShapedTextCharacters; var secondRun = layout.TextLines[0].TextRuns[1] as ShapedTextRun;
hit = layout.HitTestPoint(new Point(firstRun.Size.Width, 0)); hit = layout.HitTestPoint(new Point(firstRun.Size.Width, 0));
@ -928,7 +928,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = layout.TextLines[0]; var textLine = layout.TextLines[0];
var firstRun = (ShapedTextCharacters)textLine.TextRuns[0]; var firstRun = (ShapedTextRun)textLine.TextRuns[0];
var firstCluster = firstRun.ShapedBuffer.GlyphClusters[0]; var firstCluster = firstRun.ShapedBuffer.GlyphClusters[0];
@ -987,7 +987,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = layout.TextLines[0]; var textLine = layout.TextLines[0];
var shapedRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var shapedRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var clusters = shapedRuns.SelectMany(x => x.ShapedBuffer.GlyphClusters).ToList(); var clusters = shapedRuns.SelectMany(x => x.ShapedBuffer.GlyphClusters).ToList();

30
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -92,7 +92,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
foreach (var textRun in textLine.TextRuns.OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar)) foreach (var textRun in textLine.TextRuns.OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar))
{ {
var shapedRun = (ShapedTextCharacters)textRun; var shapedRun = (ShapedTextRun)textRun;
clusters.AddRange(shapedRun.IsReversed ? clusters.AddRange(shapedRun.IsReversed ?
shapedRun.ShapedBuffer.GlyphClusters.Reverse() : shapedRun.ShapedBuffer.GlyphClusters.Reverse() :
@ -139,7 +139,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
foreach (var textRun in textLine.TextRuns.OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar)) foreach (var textRun in textLine.TextRuns.OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar))
{ {
var shapedRun = (ShapedTextCharacters)textRun; var shapedRun = (ShapedTextRun)textRun;
clusters.AddRange(shapedRun.IsReversed ? clusters.AddRange(shapedRun.IsReversed ?
shapedRun.ShapedBuffer.GlyphClusters.Reverse() : shapedRun.ShapedBuffer.GlyphClusters.Reverse() :
@ -246,7 +246,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity, formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties)); new GenericTextParagraphProperties(defaultProperties));
var clusters = textLine.TextRuns.Cast<ShapedTextCharacters>().SelectMany(x => x.ShapedBuffer.GlyphClusters) var clusters = textLine.TextRuns.Cast<ShapedTextRun>().SelectMany(x => x.ShapedBuffer.GlyphClusters)
.ToArray(); .ToArray();
var previousCharacterHit = new CharacterHit(text.Length); var previousCharacterHit = new CharacterHit(text.Length);
@ -308,7 +308,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
foreach (var run in textLine.TextRuns) foreach (var run in textLine.TextRuns)
{ {
var textRun = (ShapedTextCharacters)run; var textRun = (ShapedTextRun)run;
var glyphRun = textRun.GlyphRun; var glyphRun = textRun.GlyphRun;
@ -634,7 +634,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity, formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties)); new GenericTextParagraphProperties(defaultProperties));
var textRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var textRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var lineWidth = textLine.WidthIncludingTrailingWhitespace; var lineWidth = textLine.WidthIncludingTrailingWhitespace;
@ -732,14 +732,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
private static bool IsRightToLeft(TextLine textLine) private static bool IsRightToLeft(TextLine textLine)
{ {
return textLine.TextRuns.Cast<ShapedTextCharacters>().Any(x => !x.ShapedBuffer.IsLeftToRight); return textLine.TextRuns.Cast<ShapedTextRun>().Any(x => !x.ShapedBuffer.IsLeftToRight);
} }
private static List<int> BuildGlyphClusters(TextLine textLine) private static List<int> BuildGlyphClusters(TextLine textLine)
{ {
var glyphClusters = new List<int>(); var glyphClusters = new List<int>();
var shapedTextRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var shapedTextRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var lastCluster = -1; var lastCluster = -1;
@ -774,7 +774,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var lastCluster = -1; var lastCluster = -1;
var shapedTextRuns = textLine.TextRuns.Cast<ShapedTextCharacters>().ToList(); var shapedTextRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
foreach (var textRun in shapedTextRuns) foreach (var textRun in shapedTextRuns)
{ {
@ -820,16 +820,16 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var text = "0123"; var text = "0123";
var shaperOption = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 0, CultureInfo.CurrentCulture); var shaperOption = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 0, CultureInfo.CurrentCulture);
var firstRun = new ShapedTextCharacters(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties); var firstRun = new ShapedTextRun(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties);
var textRuns = new List<TextRun> var textRuns = new List<TextRun>
{ {
new CustomDrawableRun(), new CustomDrawableRun(),
firstRun, firstRun,
new CustomDrawableRun(), new CustomDrawableRun(),
new ShapedTextCharacters(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties), new ShapedTextRun(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties),
new CustomDrawableRun(), new CustomDrawableRun(),
new ShapedTextCharacters(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties) new ShapedTextRun(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties)
}; };
var textSource = new FixedRunsTextSource(textRuns); var textSource = new FixedRunsTextSource(textRuns);
@ -885,14 +885,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textBounds = textLine.GetTextBounds(0, 3); var textBounds = textLine.GetTextBounds(0, 3);
var firstRun = textLine.TextRuns[0] as ShapedTextCharacters; var firstRun = textLine.TextRuns[0] as ShapedTextRun;
Assert.Equal(1, textBounds.Count); Assert.Equal(1, textBounds.Count);
Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
textBounds = textLine.GetTextBounds(3, 4); textBounds = textLine.GetTextBounds(3, 4);
var secondRun = textLine.TextRuns[1] as ShapedTextCharacters; var secondRun = textLine.TextRuns[1] as ShapedTextRun;
Assert.Equal(1, textBounds.Count); Assert.Equal(1, textBounds.Count);
Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
@ -932,14 +932,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textBounds = textLine.GetTextBounds(0, 4); var textBounds = textLine.GetTextBounds(0, 4);
var secondRun = textLine.TextRuns[1] as ShapedTextCharacters; var secondRun = textLine.TextRuns[1] as ShapedTextRun;
Assert.Equal(1, textBounds.Count); Assert.Equal(1, textBounds.Count);
Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
textBounds = textLine.GetTextBounds(4, 3); textBounds = textLine.GetTextBounds(4, 3);
var firstRun = textLine.TextRuns[0] as ShapedTextCharacters; var firstRun = textLine.TextRuns[0] as ShapedTextRun;
Assert.Equal(1, textBounds.Count); Assert.Equal(1, textBounds.Count);

Loading…
Cancel
Save