diff --git a/.editorconfig b/.editorconfig index 337760636b..9014c8938f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -141,6 +141,8 @@ dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomme dotnet_diagnostic.CA1802.severity = warning # CA1825: Avoid zero-length array allocations dotnet_diagnostic.CA1825.severity = warning +# CA1821: Remove empty finalizers +dotnet_diagnostic.CA1821.severity = warning # Wrapping preferences csharp_wrap_before_ternary_opsigns = false diff --git a/dirs.proj b/dirs.proj index a2544ef951..f1eaae8a4a 100644 --- a/dirs.proj +++ b/dirs.proj @@ -9,21 +9,18 @@ - - - - - - - + + + + - + diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml index 29cd939520..6217d39b21 100644 --- a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml @@ -13,17 +13,17 @@ Margin="16" HorizontalAlignment="Stretch" Spacing="16"> - A simple DatePicker with a header + A simple DatePicker - + - <DatePicker Header="Pick a date" /> + <DatePicker/> @@ -33,7 +33,7 @@ - + @@ -79,24 +79,24 @@ - + - A TimePicker with a header and minute increments specified. + A TimePicker with minute increments specified. - + - <TimePicker Header="Arrival time" MinuteIncrement="15" /> + <TimePicker MinuteIncrement="15" /> @@ -107,13 +107,13 @@ - + - <TimePicker ClockIdentifier="12HourClock" Header="12 hour clock" /> + <TimePicker ClockIdentifier="12HourClock" /> @@ -124,13 +124,13 @@ - + - <TimePicker ClockIdentifier="24HourClock" Header="24 hour clock" /> + <TimePicker ClockIdentifier="24HourClock" /> diff --git a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs index 674ed8e61f..5c31e138e0 100644 --- a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs +++ b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs @@ -22,7 +22,7 @@ namespace RenderDemo.Pages public class GlyphRunControl : Control { - private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface; + private IGlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface; private readonly Random _rand = new Random(); private ushort[] _glyphIndices = new ushort[1]; private char[] _characters = new char[1]; @@ -81,7 +81,7 @@ namespace RenderDemo.Pages public class GlyphRunGeometryControl : Control { - private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface; + private IGlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface; private readonly Random _rand = new Random(); private ushort[] _glyphIndices = new ushort[1]; private char[] _characters = new char[1]; diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs index 705fa3c59d..de8d02f188 100644 --- a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs @@ -9,11 +9,11 @@ using AndroidX.Lifecycle; namespace Avalonia.Android { - public abstract class AvaloniaMainActivity : AppCompatActivity + public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler { internal static object ViewContent; - internal Action ActivityResult; + public Action ActivityResult { get; set; } internal AvaloniaView View; protected override void OnCreate(Bundle savedInstanceState) @@ -24,8 +24,6 @@ namespace Avalonia.Android View.Content = ViewContent; } - View.Prepare(); - if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime) { lifetime.View = View; diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs index 94e863210b..5267843bfc 100644 --- a/src/Android/Avalonia.Android/AvaloniaView.cs +++ b/src/Android/Avalonia.Android/AvaloniaView.cs @@ -21,10 +21,7 @@ namespace Avalonia.Android { _view = new ViewImpl(this); AddView(_view.View); - } - internal void Prepare () - { _root = new EmbeddableControlRoot(_view); _root.Prepare(); } diff --git a/src/Android/Avalonia.Android/IActivityResultHandler.cs b/src/Android/Avalonia.Android/IActivityResultHandler.cs new file mode 100644 index 0000000000..14094ee185 --- /dev/null +++ b/src/Android/Avalonia.Android/IActivityResultHandler.cs @@ -0,0 +1,11 @@ +using System; +using Android.App; +using Android.Content; + +namespace Avalonia.Android +{ + public interface IActivityResultHandler + { + public Action ActivityResult { get; set; } + } +} diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 7ce72aaca5..984eb775b5 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using Android.App; using Android.Content; using Android.Graphics; using Android.Runtime; @@ -52,7 +52,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform _view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling); NativeControlHost = new AndroidNativeControlHostImpl(avaloniaView); - StorageProvider = new AndroidStorageProvider((AvaloniaMainActivity)avaloniaView.Context); + StorageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context); } public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) => diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs index ce385ebe34..6d0e6be0ad 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs @@ -15,7 +15,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers internal class AndroidMotionEventsHelper : IDisposable { private static readonly PooledList s_intermediatePointsPooledList = new(ClearMode.Never); - private static readonly float s_radiansToDegree = (float)(180f * Math.PI); + private const float RadiansToDegree = (float)(180f * Math.PI); private readonly TouchDevice _touchDevice; private readonly MouseDevice _mouseDevice; private readonly PenDevice _penDevice; @@ -223,7 +223,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers { Position = new Point(e.GetX(index), e.GetY(index)) / _view.RenderScaling, Pressure = Math.Min(e.GetPressure(index), 1), // android pressure can depend on the device, can be mixed up with "GetSize", may be larger than 1.0f on some devices - Twist = e.GetOrientation(index) * s_radiansToDegree + Twist = e.GetOrientation(index) * RadiansToDegree }; } @@ -233,7 +233,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers { Position = new Point(e.GetHistoricalX(index, pos), e.GetHistoricalY(index, pos)) / _view.RenderScaling, Pressure = Math.Min(e.GetHistoricalPressure(index, pos), 1), - Twist = e.GetHistoricalOrientation(index, pos) * s_radiansToDegree + Twist = e.GetHistoricalOrientation(index, pos) * RadiansToDegree }; } diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs index 3a1a9e76ea..62e43ff2ef 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs @@ -14,10 +14,10 @@ namespace Avalonia.Android.Platform.Storage; internal class AndroidStorageProvider : IStorageProvider { - private readonly AvaloniaMainActivity _activity; + private readonly Activity _activity; private int _lastRequestCode = 20000; - public AndroidStorageProvider(AvaloniaMainActivity activity) + public AndroidStorageProvider(Activity activity) { _activity = activity; } @@ -119,7 +119,10 @@ internal class AndroidStorageProvider : IStorageProvider var tcs = new TaskCompletionSource(); var currentRequestCode = _lastRequestCode++; - _activity.ActivityResult += OnActivityResult; + if (_activity is IActivityResultHandler mainActivity) + { + mainActivity.ActivityResult += OnActivityResult; + } _activity.StartActivityForResult(pickerIntent, currentRequestCode); var result = await tcs.Task; @@ -158,7 +161,11 @@ internal class AndroidStorageProvider : IStorageProvider return; } - _activity.ActivityResult -= OnActivityResult; + + if (_activity is IActivityResultHandler mainActivity) + { + mainActivity.ActivityResult -= OnActivityResult; + } _ = tcs.TrySetResult(resultCode == Result.Ok ? data : null); } diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 1cb29e4e37..402bc3a099 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -21,6 +21,9 @@ + + + @@ -38,7 +41,7 @@ - + diff --git a/src/Avalonia.Base/Media/FontManager.cs b/src/Avalonia.Base/Media/FontManager.cs index 37091b82e3..d92d003c2a 100644 --- a/src/Avalonia.Base/Media/FontManager.cs +++ b/src/Avalonia.Base/Media/FontManager.cs @@ -13,8 +13,8 @@ namespace Avalonia.Media /// public sealed class FontManager { - private readonly ConcurrentDictionary _glyphTypefaceCache = - new ConcurrentDictionary(); + private readonly ConcurrentDictionary _glyphTypefaceCache = + new ConcurrentDictionary(); private readonly FontFamily _defaultFontFamily; private readonly IReadOnlyList? _fontFallbacks; @@ -81,13 +81,13 @@ namespace Avalonia.Media PlatformImpl.GetInstalledFontFamilyNames(checkForUpdates); /// - /// Returns a new , or an existing one if a matching exists. + /// Returns a new , or an existing one if a matching exists. /// /// The typeface. /// - /// The . + /// The . /// - public GlyphTypeface GetOrAddGlyphTypeface(Typeface typeface) + public IGlyphTypeface GetOrAddGlyphTypeface(Typeface typeface) { while (true) { @@ -96,7 +96,7 @@ namespace Avalonia.Media return glyphTypeface; } - glyphTypeface = new GlyphTypeface(typeface); + glyphTypeface = PlatformImpl.CreateGlyphTypeface(typeface); if (_glyphTypefaceCache.TryAdd(typeface, glyphTypeface)) { diff --git a/src/Avalonia.Base/Media/FontMetrics.cs b/src/Avalonia.Base/Media/FontMetrics.cs new file mode 100644 index 0000000000..1cd01675db --- /dev/null +++ b/src/Avalonia.Base/Media/FontMetrics.cs @@ -0,0 +1,58 @@ +namespace Avalonia.Media +{ + /// + /// The font metrics is holding information about a font's ascent, descent, etc. in design em units. + /// + public readonly struct FontMetrics + { + /// + /// Gets the font design units per em. + /// + public short DesignEmHeight { get; init; } + + /// + /// A value indicating whether all glyphs in the font have the same advancement. + /// + public bool IsFixedPitch { get; init; } + + /// + /// Gets the recommended distance above the baseline in design em size. + /// + public int Ascent { get; init; } + + /// + /// Gets the recommended distance under the baseline in design em size. + /// + public int Descent { get; init; } + + /// + /// Gets the recommended additional space between two lines of text in design em size. + /// + public int LineGap { get; init; } + + /// + /// Gets the recommended line spacing of a formed text line. + /// + public int LineSpacing => Descent - Ascent + LineGap; + + /// + /// Gets a value that indicates the distance of the underline from the baseline in design em size. + /// + public int UnderlinePosition { get; init; } + + /// + /// Gets a value that indicates the thickness of the underline in design em size. + /// + public int UnderlineThickness { get; init; } + + /// + /// Gets a value that indicates the distance of the strikethrough from the baseline in design em size. + /// + public int StrikethroughPosition { get; init; } + + /// + /// Gets a value that indicates the thickness of the underline in design em size. + /// + public int StrikethroughThickness { get; init; } + } +} diff --git a/src/Avalonia.Base/Media/GlyphRun.cs b/src/Avalonia.Base/Media/GlyphRun.cs index 2289f98228..a1cb00e209 100644 --- a/src/Avalonia.Base/Media/GlyphRun.cs +++ b/src/Avalonia.Base/Media/GlyphRun.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Drawing; using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Platform; using Avalonia.Utilities; @@ -15,7 +16,7 @@ namespace Avalonia.Media private static readonly IComparer s_descendingComparer = new ReverseComparer(); private IGlyphRunImpl? _glyphRunImpl; - private GlyphTypeface _glyphTypeface; + private IGlyphTypeface _glyphTypeface; private double _fontRenderingEmSize; private int _biDiLevel; private Point? _baselineOrigin; @@ -42,7 +43,7 @@ namespace Avalonia.Media /// The glyph clusters. /// The bidi level. public GlyphRun( - GlyphTypeface glyphTypeface, + IGlyphTypeface glyphTypeface, double fontRenderingEmSize, ReadOnlySlice characters, IReadOnlyList glyphIndices, @@ -69,9 +70,9 @@ namespace Avalonia.Media } /// - /// Gets the for the . + /// Gets the for the . /// - public GlyphTypeface GlyphTypeface => _glyphTypeface; + public IGlyphTypeface GlyphTypeface => _glyphTypeface; /// /// Gets or sets the em size used for rendering the . @@ -171,7 +172,7 @@ namespace Avalonia.Media /// /// Gets the scale of the current /// - internal double Scale => FontRenderingEmSize / GlyphTypeface.DesignEmHeight; + internal double Scale => FontRenderingEmSize / GlyphTypeface.Metrics.DesignEmHeight; /// /// Returns true if the text direction is left-to-right. Otherwise, returns false. @@ -612,7 +613,7 @@ namespace Avalonia.Media /// The baseline origin. private Point CalculateBaselineOrigin() { - return new Point(0, -GlyphTypeface.Ascent * Scale); + return new Point(0, -GlyphTypeface.Metrics.Ascent * Scale); } private GlyphRunMetrics CreateGlyphRunMetrics() @@ -636,7 +637,7 @@ namespace Avalonia.Media } var isReversed = firstCluster > lastCluster; - var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale; + var height = GlyphTypeface.Metrics.LineSpacing * Scale; var widthIncludingTrailingWhitespace = 0d; var trailingWhitespaceLength = GetTrailingWhitespaceLength(isReversed, out var newLineLength, out var glyphCount); @@ -854,9 +855,87 @@ namespace Avalonia.Media throw new InvalidOperationException(); } + _glyphRunImpl = CreateGlyphRunImpl(); + } + + private IGlyphRunImpl CreateGlyphRunImpl() + { + IGlyphRunImpl glyphRunImpl; + var platformRenderInterface = AvaloniaLocator.Current.GetRequiredService(); + var count = GlyphIndices.Count; + var scale = (float)(FontRenderingEmSize / GlyphTypeface.Metrics.DesignEmHeight); + + if (GlyphOffsets == null) + { + if (GlyphTypeface.Metrics.IsFixedPitch) + { + var buffer = platformRenderInterface.AllocateGlyphRun(GlyphTypeface, (float)FontRenderingEmSize, count); + + var glyphs = buffer.GlyphIndices; + + for (int i = 0; i < glyphs.Length; i++) + { + glyphs[i] = GlyphIndices[i]; + } + + glyphRunImpl = buffer.Build(); + } + else + { + var buffer = platformRenderInterface.AllocateHorizontalGlyphRun(GlyphTypeface, (float)FontRenderingEmSize, count); + var glyphs = buffer.GlyphIndices; + var positions = buffer.GlyphPositions; + var width = 0d; + + for (var i = 0; i < count; i++) + { + positions[i] = (float)width; + + if (GlyphAdvances == null) + { + width += GlyphTypeface.GetGlyphAdvance(GlyphIndices[i]) * scale; + } + else + { + width += GlyphAdvances[i]; + } + + glyphs[i] = GlyphIndices[i]; + } + + glyphRunImpl = buffer.Build(); + } + } + else + { + var buffer = platformRenderInterface.AllocatePositionedGlyphRun(GlyphTypeface, (float)FontRenderingEmSize, count); + var glyphs = buffer.GlyphIndices; + var glyphPositions = buffer.GlyphPositions; + var currentX = 0.0; + + for (var i = 0; i < count; i++) + { + var glyphOffset = GlyphOffsets[i]; + + glyphPositions[i] = new PointF((float)(currentX + glyphOffset.X), (float)glyphOffset.Y); + + if (GlyphAdvances == null) + { + currentX += GlyphTypeface.GetGlyphAdvance(GlyphIndices[i]) * scale; + } + else + { + currentX += GlyphAdvances[i]; + } + + glyphs[i] = GlyphIndices[i]; + } + + glyphRunImpl = buffer.Build(); + } - _glyphRunImpl = platformRenderInterface.CreateGlyphRun(this); + return glyphRunImpl; } void IDisposable.Dispose() diff --git a/src/Avalonia.Base/Media/GlyphTypeface.cs b/src/Avalonia.Base/Media/GlyphTypeface.cs deleted file mode 100644 index 45ef04e77f..0000000000 --- a/src/Avalonia.Base/Media/GlyphTypeface.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using Avalonia.Platform; - -namespace Avalonia.Media -{ - public sealed class GlyphTypeface : IDisposable - { - public GlyphTypeface(Typeface typeface) - : this(FontManager.Current.PlatformImpl.CreateGlyphTypeface(typeface)) - { - } - - public GlyphTypeface(IGlyphTypefaceImpl platformImpl) - { - PlatformImpl = platformImpl; - } - - public IGlyphTypefaceImpl PlatformImpl { get; } - - /// - /// Gets the font design units per em. - /// - public short DesignEmHeight => PlatformImpl.DesignEmHeight; - - /// - /// Gets the recommended distance above the baseline in design em size. - /// - public int Ascent => PlatformImpl.Ascent; - - /// - /// Gets the recommended distance under the baseline in design em size. - /// - public int Descent => PlatformImpl.Descent; - - /// - /// Gets the recommended additional space between two lines of text in design em size. - /// - public int LineGap => PlatformImpl.LineGap; - - /// - /// Gets the recommended line height. - /// - public int LineHeight => Descent - Ascent + LineGap; - - /// - /// Gets a value that indicates the distance of the underline from the baseline in design em size. - /// - public int UnderlinePosition => PlatformImpl.UnderlinePosition; - - /// - /// Gets a value that indicates the thickness of the underline in design em size. - /// - public int UnderlineThickness => PlatformImpl.UnderlineThickness; - - /// - /// Gets a value that indicates the distance of the strikethrough from the baseline in design em size. - /// - public int StrikethroughPosition => PlatformImpl.StrikethroughPosition; - - /// - /// Gets a value that indicates the thickness of the underline in design em size. - /// - public int StrikethroughThickness => PlatformImpl.StrikethroughThickness; - - /// - /// A value indicating whether all glyphs in the font have the same advancement. - /// - public bool IsFixedPitch => PlatformImpl.IsFixedPitch; - - /// - /// Returns an glyph index for the specified codepoint. - /// - /// - /// Returns a replacement glyph if a glyph isn't found. - /// - /// The codepoint. - /// - /// A glyph index. - /// - public ushort GetGlyph(uint codepoint) => PlatformImpl.GetGlyph(codepoint); - - /// - /// Tries to get an glyph index for specified codepoint. - /// - /// The codepoint. - /// A glyph index. - /// - /// true if an glyph index was found, false otherwise. - /// - public bool TryGetGlyph(uint codepoint, out ushort glyph) - { - glyph = PlatformImpl.GetGlyph(codepoint); - - return glyph != 0; - } - - /// - /// Returns an array of glyph indices. Codepoints that are not represented by the font are returned as 0. - /// - /// The codepoints to map. - /// - public ushort[] GetGlyphs(ReadOnlySpan codepoints) => PlatformImpl.GetGlyphs(codepoints); - - /// - /// Returns the glyph advance for the specified glyph. - /// - /// The glyph. - /// - /// The advance. - /// - public int GetGlyphAdvance(ushort glyph) => PlatformImpl.GetGlyphAdvance(glyph); - - /// - /// Returns an array of glyph advances in design em size. - /// - /// The glyph indices. - /// - public int[] GetGlyphAdvances(ReadOnlySpan glyphs) => PlatformImpl.GetGlyphAdvances(glyphs); - - void IDisposable.Dispose() - { - PlatformImpl?.Dispose(); - } - } -} diff --git a/src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs b/src/Avalonia.Base/Media/IGlyphTypeface.cs similarity index 52% rename from src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs rename to src/Avalonia.Base/Media/IGlyphTypeface.cs index 415f34fb29..de2a2309ee 100644 --- a/src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs +++ b/src/Avalonia.Base/Media/IGlyphTypeface.cs @@ -1,55 +1,23 @@ using System; using Avalonia.Metadata; -namespace Avalonia.Platform +namespace Avalonia.Media { [Unstable] - public interface IGlyphTypefaceImpl : IDisposable + public interface IGlyphTypeface : IDisposable { /// - /// Gets the font design units per em. + /// Gets the number of glyphs held by this glyph typeface. /// - short DesignEmHeight { get; } + int GlyphCount { get; } /// - /// Gets the recommended distance above the baseline in design em size. + /// Gets the font metrics. /// - int Ascent { get; } - - /// - /// Gets the recommended distance under the baseline in design em size. - /// - int Descent { get; } - - /// - /// Gets the recommended additional space between two lines of text in design em size. - /// - int LineGap { get; } - - /// - /// Gets a value that indicates the distance of the underline from the baseline in design em size. - /// - int UnderlinePosition { get; } - - /// - /// Gets a value that indicates the thickness of the underline in design em size. - /// - int UnderlineThickness { get; } - - /// - /// Gets a value that indicates the distance of the strikethrough from the baseline in design em size. - /// - int StrikethroughPosition { get; } - - /// - /// Gets a value that indicates the thickness of the underline in design em size. - /// - int StrikethroughThickness { get; } - - /// - /// A value indicating whether all glyphs in the font have the same advancement. - /// - bool IsFixedPitch { get; } + /// + /// The font metrics. + /// + FontMetrics Metrics { get; } /// /// Returns an glyph index for the specified codepoint. @@ -63,6 +31,16 @@ namespace Avalonia.Platform /// ushort GetGlyph(uint codepoint); + /// + /// Tries to get an glyph index for specified codepoint. + /// + /// The codepoint. + /// A glyph index. + /// + /// true if an glyph index was found, false otherwise. + /// + bool TryGetGlyph(uint codepoint, out ushort glyph); + /// /// Returns an array of glyph indices. Codepoints that are not represented by the font are returned as 0. /// @@ -89,5 +67,13 @@ namespace Avalonia.Platform /// An array of glyph advances. /// int[] GetGlyphAdvances(ReadOnlySpan glyphs); + + /// + /// Returns the contents of the table data for the specified tag. + /// + /// The table tag to get the data for. + /// The contents of the table data for the specified tag. + /// Returns true if the content exists, otherwise false. + bool TryGetTable(uint tag, out byte[] table); } } diff --git a/src/Avalonia.Base/Media/TextDecoration.cs b/src/Avalonia.Base/Media/TextDecoration.cs index 4c9764af96..0a7328125a 100644 --- a/src/Avalonia.Base/Media/TextDecoration.cs +++ b/src/Avalonia.Base/Media/TextDecoration.cs @@ -155,9 +155,9 @@ namespace Avalonia.Media /// /// The drawing context. /// The decorated run. - /// The font metrics of the decorated run. + /// The font metrics of the decorated run. /// The default brush that is used to draw the decoration. - internal void Draw(DrawingContext drawingContext, GlyphRun glyphRun, FontMetrics fontMetrics, IBrush defaultBrush) + internal void Draw(DrawingContext drawingContext, GlyphRun glyphRun, TextMetrics textMetrics, IBrush defaultBrush) { var baselineOrigin = glyphRun.BaselineOrigin; var thickness = StrokeThickness; @@ -168,16 +168,16 @@ namespace Avalonia.Media switch (Location) { case TextDecorationLocation.Underline: - thickness = fontMetrics.UnderlineThickness; + thickness = textMetrics.UnderlineThickness; break; case TextDecorationLocation.Strikethrough: - thickness = fontMetrics.StrikethroughThickness; + thickness = textMetrics.StrikethroughThickness; break; } break; case TextDecorationUnit.FontRenderingEmSize: - thickness = fontMetrics.FontRenderingEmSize * thickness; + thickness = textMetrics.FontRenderingEmSize * thickness; break; } @@ -189,17 +189,17 @@ namespace Avalonia.Media origin += glyphRun.BaselineOrigin; break; case TextDecorationLocation.Strikethrough: - origin += new Point(baselineOrigin.X, baselineOrigin.Y + fontMetrics.StrikethroughPosition); + origin += new Point(baselineOrigin.X, baselineOrigin.Y + textMetrics.StrikethroughPosition); break; case TextDecorationLocation.Underline: - origin += new Point(baselineOrigin.X, baselineOrigin.Y + fontMetrics.UnderlinePosition); + origin += new Point(baselineOrigin.X, baselineOrigin.Y + textMetrics.UnderlinePosition); break; } switch (StrokeOffsetUnit) { case TextDecorationUnit.FontRenderingEmSize: - origin += new Point(0, StrokeOffset * fontMetrics.FontRenderingEmSize); + origin += new Point(0, StrokeOffset * textMetrics.FontRenderingEmSize); break; case TextDecorationUnit.Pixel: origin += new Point(0, StrokeOffset); diff --git a/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs b/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs index 47a6334e39..85924a3d32 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs +++ b/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs @@ -8,13 +8,13 @@ namespace Avalonia.Media.TextFormatting { private static readonly IComparer s_clusterComparer = new CompareClusters(); - public ShapedBuffer(ReadOnlySlice text, int length, GlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) + public ShapedBuffer(ReadOnlySlice text, int length, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) : this(text, new GlyphInfo[length], glyphTypeface, fontRenderingEmSize, bidiLevel) { } - internal ShapedBuffer(ReadOnlySlice text, ArraySlice glyphInfos, GlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) + internal ShapedBuffer(ReadOnlySlice text, ArraySlice glyphInfos, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) { Text = text; GlyphInfos = glyphInfos; @@ -29,7 +29,7 @@ namespace Avalonia.Media.TextFormatting public int Length => GlyphInfos.Length; - public GlyphTypeface GlyphTypeface { get; } + public IGlyphTypeface GlyphTypeface { get; } public double FontRenderingEmSize { get; } diff --git a/src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs index 53287a264d..21101f462c 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs +++ b/src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Utilities; @@ -18,7 +17,7 @@ namespace Avalonia.Media.TextFormatting Text = shapedBuffer.Text; Properties = properties; TextSourceLength = Text.Length; - FontMetrics = new FontMetrics(properties.Typeface, properties.FontRenderingEmSize); + TextMetrics = new TextMetrics(properties.Typeface, properties.FontRenderingEmSize); } public bool IsReversed { get; private set; } @@ -36,9 +35,9 @@ namespace Avalonia.Media.TextFormatting /// public override int TextSourceLength { get; } - public FontMetrics FontMetrics { get; } + public TextMetrics TextMetrics { get; } - public override double Baseline => -FontMetrics.Ascent; + public override double Baseline => -TextMetrics.Ascent; public override Size Size => GlyphRun.Size; @@ -89,7 +88,7 @@ namespace Avalonia.Media.TextFormatting foreach (var textDecoration in Properties.TextDecorations) { - textDecoration.Draw(drawingContext, GlyphRun, FontMetrics, Properties.ForegroundBrush); + textDecoration.Draw(drawingContext, GlyphRun, TextMetrics, Properties.ForegroundBrush); } } } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index aba8008fb9..96f88d1f44 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -1378,17 +1378,17 @@ namespace Avalonia.Media.TextFormatting private TextLineMetrics CreateLineMetrics() { - var glyphTypeface = _paragraphProperties.DefaultTextRunProperties.Typeface.GlyphTypeface; + var fontMetrics = _paragraphProperties.DefaultTextRunProperties.Typeface.GlyphTypeface.Metrics; var fontRenderingEmSize = _paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize; - var scale = fontRenderingEmSize / glyphTypeface.DesignEmHeight; + var scale = fontRenderingEmSize / fontMetrics.DesignEmHeight; var width = 0d; var widthIncludingWhitespace = 0d; var trailingWhitespaceLength = 0; var newLineLength = 0; - var ascent = glyphTypeface.Ascent * scale; - var descent = glyphTypeface.Descent * scale; - var lineGap = glyphTypeface.LineGap * scale; + var ascent = fontMetrics.Ascent * scale; + var descent = fontMetrics.Descent * scale; + var lineGap = fontMetrics.LineGap * scale; var height = descent - ascent + lineGap; @@ -1400,26 +1400,26 @@ namespace Avalonia.Media.TextFormatting { case ShapedTextCharacters textRun: { - var fontMetrics = - new FontMetrics(textRun.Properties.Typeface, textRun.Properties.FontRenderingEmSize); + var textMetrics = + new TextMetrics(textRun.Properties.Typeface, textRun.Properties.FontRenderingEmSize); if (fontRenderingEmSize < textRun.Properties.FontRenderingEmSize) { fontRenderingEmSize = textRun.Properties.FontRenderingEmSize; - if (ascent > fontMetrics.Ascent) + if (ascent > textMetrics.Ascent) { - ascent = fontMetrics.Ascent; + ascent = textMetrics.Ascent; } - if (descent < fontMetrics.Descent) + if (descent < textMetrics.Descent) { - descent = fontMetrics.Descent; + descent = textMetrics.Descent; } - if (lineGap < fontMetrics.LineGap) + if (lineGap < textMetrics.LineGap) { - lineGap = fontMetrics.LineGap; + lineGap = textMetrics.LineGap; } if (descent - ascent + lineGap > height) diff --git a/src/Avalonia.Base/Media/TextFormatting/FontMetrics.cs b/src/Avalonia.Base/Media/TextFormatting/TextMetrics.cs similarity index 69% rename from src/Avalonia.Base/Media/TextFormatting/FontMetrics.cs rename to src/Avalonia.Base/Media/TextFormatting/TextMetrics.cs index e01bba00a4..0382e66b5a 100644 --- a/src/Avalonia.Base/Media/TextFormatting/FontMetrics.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextMetrics.cs @@ -1,33 +1,33 @@ namespace Avalonia.Media.TextFormatting { /// - /// A metric that holds information about font specific measurements. + /// A metric that holds information about text specific measurements. /// - public readonly struct FontMetrics + public readonly struct TextMetrics { - public FontMetrics(Typeface typeface, double fontRenderingEmSize) + public TextMetrics(Typeface typeface, double fontRenderingEmSize) { - var glyphTypeface = typeface.GlyphTypeface; + var fontMetrics = typeface.GlyphTypeface.Metrics; - var scale = fontRenderingEmSize / glyphTypeface.DesignEmHeight; + var scale = fontRenderingEmSize / fontMetrics.DesignEmHeight; FontRenderingEmSize = fontRenderingEmSize; - Ascent = glyphTypeface.Ascent * scale; + Ascent = fontMetrics.Ascent * scale; - Descent = glyphTypeface.Descent * scale; + Descent = fontMetrics.Descent * scale; - LineGap = glyphTypeface.LineGap * scale; + LineGap = fontMetrics.LineGap * scale; LineHeight = Descent - Ascent + LineGap; - UnderlineThickness = glyphTypeface.UnderlineThickness * scale; + UnderlineThickness = fontMetrics.UnderlineThickness * scale; - UnderlinePosition = glyphTypeface.UnderlinePosition * scale; + UnderlinePosition = fontMetrics.UnderlinePosition * scale; - StrikethroughThickness = glyphTypeface.StrikethroughThickness * scale; + StrikethroughThickness = fontMetrics.StrikethroughThickness * scale; - StrikethroughPosition = glyphTypeface.StrikethroughPosition * scale; + StrikethroughPosition = fontMetrics.StrikethroughPosition * scale; } /// diff --git a/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs b/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs index 4e75bb921e..0d00bed51e 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs @@ -8,7 +8,7 @@ namespace Avalonia.Media.TextFormatting public readonly struct TextShaperOptions { public TextShaperOptions( - GlyphTypeface typeface, + IGlyphTypeface typeface, double fontRenderingEmSize = 12, sbyte bidiLevel = 0, CultureInfo? culture = null, @@ -24,7 +24,7 @@ namespace Avalonia.Media.TextFormatting /// /// Get the typeface. /// - public GlyphTypeface Typeface { get; } + public IGlyphTypeface Typeface { get; } /// /// Get the font rendering em size. /// diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs index ce9cdde044..de40839853 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs @@ -1,4 +1,5 @@ -using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; using Avalonia.Utilities; namespace Avalonia.Media.TextFormatting.Unicode @@ -165,7 +166,7 @@ namespace Avalonia.Media.TextFormatting.Unicode /// The index to read at. /// The count of character that were read. /// - public static Codepoint ReadAt(ReadOnlySlice text, int index, out int count) + public static Codepoint ReadAt(ReadOnlySpan text, int index, out int count) { count = 1; diff --git a/src/Avalonia.Base/Media/Typeface.cs b/src/Avalonia.Base/Media/Typeface.cs index f0daa841d9..e6047bf96c 100644 --- a/src/Avalonia.Base/Media/Typeface.cs +++ b/src/Avalonia.Base/Media/Typeface.cs @@ -81,7 +81,7 @@ namespace Avalonia.Media /// /// The glyph typeface. /// - public GlyphTypeface GlyphTypeface => FontManager.Current.GetOrAddGlyphTypeface(this); + public IGlyphTypeface GlyphTypeface => FontManager.Current.GetOrAddGlyphTypeface(this); public static bool operator !=(Typeface a, Typeface b) { diff --git a/src/Avalonia.Base/Platform/IFontManagerImpl.cs b/src/Avalonia.Base/Platform/IFontManagerImpl.cs index 932249bd52..cd6e64abaf 100644 --- a/src/Avalonia.Base/Platform/IFontManagerImpl.cs +++ b/src/Avalonia.Base/Platform/IFontManagerImpl.cs @@ -43,6 +43,6 @@ namespace Avalonia.Platform /// 0 /// The created glyph typeface. Can be Null if it was not possible to create a glyph typeface. /// - IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface); + IGlyphTypeface CreateGlyphTypeface(Typeface typeface); } } diff --git a/src/Avalonia.Base/Platform/IGlyphRunBuffer.cs b/src/Avalonia.Base/Platform/IGlyphRunBuffer.cs new file mode 100644 index 0000000000..c1fc7a5967 --- /dev/null +++ b/src/Avalonia.Base/Platform/IGlyphRunBuffer.cs @@ -0,0 +1,22 @@ +using System; +using System.Drawing; + +namespace Avalonia.Platform +{ + public interface IGlyphRunBuffer + { + Span GlyphIndices { get; } + + IGlyphRunImpl Build(); + } + + public interface IHorizontalGlyphRunBuffer : IGlyphRunBuffer + { + Span GlyphPositions { get; } + } + + public interface IPositionedGlyphRunBuffer : IGlyphRunBuffer + { + Span GlyphPositions { get; } + } +} diff --git a/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs index e39a4e23df..9d0d7974b4 100644 --- a/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs @@ -171,11 +171,40 @@ namespace Avalonia.Platform IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride); /// - /// Creates a platform implementation of a glyph run. + /// Allocates a platform glyph run buffer. /// - /// The glyph run. - /// - IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun); + /// The glyph typeface. + /// The font rendering em size. + /// The length. + /// An . + /// + /// This buffer only holds glyph indices. + /// + IGlyphRunBuffer AllocateGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length); + + /// + /// Allocates a horizontal platform glyph run buffer. + /// + /// The glyph typeface. + /// The font rendering em size. + /// The length. + /// An . + /// + /// This buffer holds glyph indices and glyph advances. + /// + IHorizontalGlyphRunBuffer AllocateHorizontalGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length); + + /// + /// Allocates a positioned platform glyph run buffer. + /// + /// The glyph typeface. + /// The font rendering em size. + /// The length. + /// An . + /// + /// This buffer holds glyph indices, glyph advances and glyph positions. + /// + IPositionedGlyphRunBuffer AllocatePositionedGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length); /// /// Gets a value indicating whether the platform directly supports rectangles with rounded corners. diff --git a/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs b/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs index b0b3982ed5..06fb526736 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs @@ -25,7 +25,7 @@ internal class FpsCounter // ASCII chars private GlyphRun[] _runs = new GlyphRun[LastChar - FirstChar + 1]; - public FpsCounter(GlyphTypeface typeface) + public FpsCounter(IGlyphTypeface typeface) { for (var c = FirstChar; c <= LastChar; c++) { diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs index 3c48c3469e..feb1097b5f 100644 --- a/src/Avalonia.Base/Utilities/MathUtilities.cs +++ b/src/Avalonia.Base/Utilities/MathUtilities.cs @@ -11,7 +11,7 @@ namespace Avalonia.Utilities static class MathUtilities { // smallest such that 1.0+DoubleEpsilon != 1.0 - internal static readonly double DoubleEpsilon = 2.2204460492503131e-016; + internal const double DoubleEpsilon = 2.2204460492503131e-016; private const float FloatEpsilon = 1.192092896e-07F; diff --git a/src/Avalonia.Base/Utilities/ReadOnlySlice.cs b/src/Avalonia.Base/Utilities/ReadOnlySlice.cs index ad545b2923..583a3139b9 100644 --- a/src/Avalonia.Base/Utilities/ReadOnlySlice.cs +++ b/src/Avalonia.Base/Utilities/ReadOnlySlice.cs @@ -214,6 +214,8 @@ namespace Avalonia.Utilities return new ReadOnlySlice(memory); } + public static implicit operator ReadOnlySpan(ReadOnlySlice slice) => slice.Span; + internal class ReadOnlySliceDebugView { private readonly ReadOnlySlice _readOnlySlice; diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs index 906ec661ae..30517f4b00 100644 --- a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs +++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs @@ -3412,23 +3412,30 @@ namespace Avalonia.Collections RefreshOrDefer(); return; } - - object addedItem = args.NewItems?[0]; - object removedItem = args.OldItems?[0]; - + // fire notifications for removes - if (args.Action == NotifyCollectionChangedAction.Remove || - args.Action == NotifyCollectionChangedAction.Replace) + if (args.OldItems != null && + (args.Action == NotifyCollectionChangedAction.Remove || + args.Action == NotifyCollectionChangedAction.Replace)) { - ProcessRemoveEvent(removedItem, args.Action == NotifyCollectionChangedAction.Replace); + foreach (var removedItem in args.OldItems) + { + ProcessRemoveEvent(removedItem, args.Action == NotifyCollectionChangedAction.Replace); + } } // fire notifications for adds - if ((args.Action == NotifyCollectionChangedAction.Add || - args.Action == NotifyCollectionChangedAction.Replace) && - (Filter == null || PassesFilter(addedItem))) + if (args.NewItems != null && + (args.Action == NotifyCollectionChangedAction.Add || + args.Action == NotifyCollectionChangedAction.Replace)) { - ProcessAddEvent(addedItem, args.NewStartingIndex); + for (var i = 0; i < args.NewItems.Count; i++) + { + if (Filter == null || PassesFilter(args.NewItems[i])) + { + ProcessAddEvent(args.NewItems[i], args.NewStartingIndex + i); + } + } } if (args.Action != NotifyCollectionChangedAction.Replace) { diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs index fb27feb521..bb05cd1b1f 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs @@ -40,18 +40,6 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect(nameof(DayVisible), x => x.DayVisible, (x, v) => x.DayVisible = v); - /// - /// Defines the Property - /// - public static readonly StyledProperty HeaderProperty = - AvaloniaProperty.Register(nameof(Header)); - - /// - /// Defines the Property - /// - public static readonly StyledProperty HeaderTemplateProperty = - AvaloniaProperty.Register(nameof(HeaderTemplate)); - /// /// Defines the Property /// @@ -152,24 +140,6 @@ namespace Avalonia.Controls } } - /// - /// Gets or sets the DatePicker header - /// - public object Header - { - get => GetValue(HeaderProperty); - set => SetValue(HeaderProperty, value); - } - - /// - /// Gets or sets the header template - /// - public IDataTemplate HeaderTemplate - { - get => GetValue(HeaderTemplateProperty); - set => SetValue(HeaderTemplateProperty, value); - } - /// /// Gets or sets the maximum year for the picker /// diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index a709e4fb49..228b9ae205 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -34,18 +34,6 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect(nameof(MinuteIncrement), x => x.MinuteIncrement, (x, v) => x.MinuteIncrement = v); - /// - /// Defines the property - /// - public static readonly StyledProperty HeaderProperty = - AvaloniaProperty.Register(nameof(Header)); - - /// - /// Defines the property - /// - public static readonly StyledProperty HeaderTemplateProperty = - AvaloniaProperty.Register(nameof(HeaderTemplate)); - /// /// Defines the property /// @@ -103,24 +91,6 @@ namespace Avalonia.Controls } } - /// - /// Gets or sets the header - /// - public object Header - { - get => GetValue(HeaderProperty); - set => SetValue(HeaderProperty, value); - } - - /// - /// Gets or sets the header template - /// - public IDataTemplate HeaderTemplate - { - get => GetValue(HeaderTemplateProperty); - set => SetValue(HeaderTemplateProperty, value); - } - /// /// Gets or sets the clock identifier, either 12HourClock or 24HourClock /// diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index e6677194b0..7d4a6518ef 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -191,7 +191,7 @@ namespace Avalonia.DesignerSupport.Remote public Task ClearAsync() => Task.CompletedTask; public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask; - public Task GetFormatsAsync() => Task.FromResult(new string[0]); + public Task GetFormatsAsync() => Task.FromResult(Array.Empty()); public Task GetDataAsync(string format) => Task.FromResult((object)null); } diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs index cb23c6c336..fcd7f1e31f 100644 --- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs +++ b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs @@ -110,14 +110,24 @@ namespace Avalonia.Headless return new HeadlessBitmapStub(destinationSize, new Vector(96, 96)); } - public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun) + public IGeometryImpl BuildGlyphRunGeometry(GlyphRun glyphRun) { - return new HeadlessGlyphRunStub(); + return new HeadlessGeometryStub(new Rect(glyphRun.Size)); } - public IGeometryImpl BuildGlyphRunGeometry(GlyphRun glyphRun) + public IGlyphRunBuffer AllocateGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length) { - return new HeadlessGeometryStub(new Rect(glyphRun.Size)); + return new HeadlessGlyphRunBufferStub(); + } + + public IHorizontalGlyphRunBuffer AllocateHorizontalGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length) + { + return new HeadlessHorizontalGlyphRunBufferStub(); + } + + public IPositionedGlyphRunBuffer AllocatePositionedGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length) + { + return new HeadlessPositionedGlyphRunBufferStub(); } class HeadlessGeometryStub : IGeometryImpl @@ -203,6 +213,26 @@ namespace Avalonia.Headless public Matrix Transform { get; } } + class HeadlessGlyphRunBufferStub : IGlyphRunBuffer + { + public Span GlyphIndices => Span.Empty; + + public IGlyphRunImpl Build() + { + return new HeadlessGlyphRunStub(); + } + } + + class HeadlessHorizontalGlyphRunBufferStub : HeadlessGlyphRunBufferStub, IHorizontalGlyphRunBuffer + { + public Span GlyphPositions => Span.Empty; + } + + class HeadlessPositionedGlyphRunBufferStub : HeadlessGlyphRunBufferStub, IPositionedGlyphRunBuffer + { + public Span GlyphPositions => Span.Empty; + } + class HeadlessGlyphRunStub : IGlyphRunImpl { public void Dispose() diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs index ed51529a96..c8ac947c16 100644 --- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs +++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs @@ -75,8 +75,13 @@ namespace Avalonia.Headless public TimeSpan TouchDoubleClickTime => DoubleClickTime; } - class HeadlessGlyphTypefaceImpl : IGlyphTypefaceImpl + class HeadlessGlyphTypefaceImpl : IGlyphTypeface { + public FontMetrics Metrics => new FontMetrics + { + + }; + public short DesignEmHeight => 10; public int Ascent => 5; @@ -95,6 +100,8 @@ namespace Avalonia.Headless public bool IsFixedPitch => true; + public int GlyphCount => 1337; + public void Dispose() { } @@ -104,6 +111,13 @@ namespace Avalonia.Headless return 1; } + public bool TryGetGlyph(uint codepoint, out ushort glyph) + { + glyph = 1; + + return true; + } + public int GetGlyphAdvance(ushort glyph) { return 1; @@ -118,6 +132,12 @@ namespace Avalonia.Headless { return codepoints.ToArray().Select(x => (ushort)x).ToArray(); } + + public bool TryGetTable(uint tag, out byte[] table) + { + table = null; + return false; + } } class HeadlessTextShaperStub : ITextShaperImpl @@ -134,7 +154,7 @@ namespace Avalonia.Headless class HeadlessFontManagerStub : IFontManagerImpl { - public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) + public IGlyphTypeface CreateGlyphTypeface(Typeface typeface) { return new HeadlessGlyphTypefaceImpl(); } diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml index 88b9f18eee..e480fb1670 100644 --- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml @@ -358,7 +358,6 @@ 4 2 0 - Normal @@ -375,8 +374,6 @@ - - @@ -424,7 +421,6 @@ - @@ -455,8 +451,6 @@ - - @@ -595,7 +589,6 @@ - diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml index b51a0bf259..4f421f64a7 100644 --- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml @@ -354,7 +354,6 @@ 4 2 0 - Normal @@ -371,8 +370,6 @@ - - @@ -420,7 +417,6 @@ - @@ -450,8 +446,6 @@ - - @@ -589,7 +583,6 @@ - diff --git a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml index 6f1e4fccfe..1585dada90 100644 --- a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml @@ -28,7 +28,6 @@ - 0,0,0,4 40 40 41 @@ -84,18 +83,8 @@ - - - +