From 876fa088124941aeb60e81f00bdb2bf3a26b882a Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 4 Jan 2023 10:18:35 +1100 Subject: [PATCH 01/30] move to a consistent langversion of 11 --- Directory.Build.props | 1 + build/SharedVersion.props | 1 - src/Browser/Avalonia.Browser/Avalonia.Browser.csproj | 1 - src/tools/DevAnalyzers/DevAnalyzers.csproj | 1 - src/tools/DevGenerators/DevGenerators.csproj | 1 - tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj | 1 - .../Avalonia.Controls.DataGrid.UnitTests.csproj | 1 - .../Avalonia.Controls.UnitTests.csproj | 1 - .../Avalonia.Markup.Xaml.UnitTests.csproj | 1 - tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj | 1 - tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj | 1 - 11 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 42daa2df7f..c19a55e8ea 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,5 +7,6 @@ false false False + 11 diff --git a/build/SharedVersion.props b/build/SharedVersion.props index e9c3d65b41..eca3ba37b0 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -8,7 +8,6 @@ https://github.com/AvaloniaUI/Avalonia/ true $(NoWarn);CS1591 - preview MIT Icon.png Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly. diff --git a/src/Browser/Avalonia.Browser/Avalonia.Browser.csproj b/src/Browser/Avalonia.Browser/Avalonia.Browser.csproj index 014d387cb2..2fc3cc885a 100644 --- a/src/Browser/Avalonia.Browser/Avalonia.Browser.csproj +++ b/src/Browser/Avalonia.Browser/Avalonia.Browser.csproj @@ -1,7 +1,6 @@ net7.0 - preview enable true diff --git a/src/tools/DevAnalyzers/DevAnalyzers.csproj b/src/tools/DevAnalyzers/DevAnalyzers.csproj index 53e3e74e76..e5c2fc6cf6 100644 --- a/src/tools/DevAnalyzers/DevAnalyzers.csproj +++ b/src/tools/DevAnalyzers/DevAnalyzers.csproj @@ -2,7 +2,6 @@ netstandard2.0 - 10 enable diff --git a/src/tools/DevGenerators/DevGenerators.csproj b/src/tools/DevGenerators/DevGenerators.csproj index 069ff159fc..30da940514 100644 --- a/src/tools/DevGenerators/DevGenerators.csproj +++ b/src/tools/DevGenerators/DevGenerators.csproj @@ -4,7 +4,6 @@ netstandard2.0 enable false - 10 diff --git a/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj b/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj index 0162f53f5e..4cdce8df26 100644 --- a/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj +++ b/tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj @@ -3,7 +3,6 @@ net6.0 Library true - latest diff --git a/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj b/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj index eb1bf24d0c..20c2f711ad 100644 --- a/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj +++ b/tests/Avalonia.Controls.DataGrid.UnitTests/Avalonia.Controls.DataGrid.UnitTests.csproj @@ -1,7 +1,6 @@ net6.0 - latest Library true diff --git a/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj b/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj index 12eb290fde..471f19f948 100644 --- a/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj +++ b/tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj @@ -1,7 +1,6 @@ ๏ปฟ net6.0 - latest Library true diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj index 6dce5eaab5..fa4957c24c 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj @@ -3,7 +3,6 @@ net6.0;net47 Library true - latest diff --git a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj index ccde66a50e..ea91b8c196 100644 --- a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj +++ b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj @@ -1,7 +1,6 @@ ๏ปฟ net6.0 - latest diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj index cb6884cad8..b9c2a619d9 100644 --- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj +++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj @@ -1,7 +1,6 @@ ๏ปฟ netstandard2.0 - latest false Library false From e049313e7a563b3ab65ad679980309aca34af14a Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Thu, 5 Jan 2023 20:50:34 +1100 Subject: [PATCH 02/30] Microsoft.Build.Traversal 3.2.0 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index e4a0cc20c2..8536535b51 100644 --- a/global.json +++ b/global.json @@ -4,6 +4,6 @@ "rollForward": "latestFeature" }, "msbuild-sdks": { - "Microsoft.Build.Traversal": "1.0.43" + "Microsoft.Build.Traversal": "3.2.0" } } From 5fef8af151e7673264f20a41e96c97a2a4846a68 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Thu, 5 Jan 2023 18:31:02 +0300 Subject: [PATCH 03/30] [Text] [Rename] ShapeableTextCharacters to UnshapedTextRun and ShapedTextCharacters to ShapedTextRun --- .../TextFormatting/InterWordJustification.cs | 2 +- ...apedTextCharacters.cs => ShapedTextRun.cs} | 12 +++--- .../Media/TextFormatting/TextCharacters.cs | 18 ++++----- .../TextFormatting/TextEllipsisHelper.cs | 2 +- .../Media/TextFormatting/TextFormatterImpl.cs | 28 ++++++------- .../TextLeadingPrefixCharacterEllipsis.cs | 4 +- .../Media/TextFormatting/TextLineImpl.cs | 40 +++++++++---------- ...leTextCharacters.cs => UnshapedTextRun.cs} | 16 ++++---- .../TextFormatting/TextFormatterTests.cs | 4 +- .../Media/TextFormatting/TextLayoutTests.cs | 28 ++++++------- .../Media/TextFormatting/TextLineTests.cs | 30 +++++++------- 11 files changed, 92 insertions(+), 92 deletions(-) rename src/Avalonia.Base/Media/TextFormatting/{ShapedTextCharacters.cs => ShapedTextRun.cs} (92%) rename src/Avalonia.Base/Media/TextFormatting/{ShapeableTextCharacters.cs => UnshapedTextRun.cs} (61%) diff --git a/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs b/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs index 3c3a46c209..21e8ce089a 100644 --- a/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs +++ b/src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs @@ -91,7 +91,7 @@ namespace Avalonia.Media.TextFormatting continue; } - if (textRun is ShapedTextCharacters shapedText) + if (textRun is ShapedTextRun shapedText) { var glyphRun = shapedText.GlyphRun; var shapedBuffer = shapedText.ShapedBuffer; diff --git a/src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs similarity index 92% rename from src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs rename to src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs index 3035eb7b18..3149bc2cda 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ShapedTextCharacters.cs +++ b/src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs @@ -6,11 +6,11 @@ namespace Avalonia.Media.TextFormatting /// /// A text run that holds shaped characters. /// - public sealed class ShapedTextCharacters : DrawableTextRun + public sealed class ShapedTextRun : DrawableTextRun { private GlyphRun? _glyphRun; - public ShapedTextCharacters(ShapedBuffer shapedBuffer, TextRunProperties properties) + public ShapedTextRun(ShapedBuffer shapedBuffer, TextRunProperties properties) { ShapedBuffer = shapedBuffer; CharacterBufferReference = shapedBuffer.CharacterBufferRange.CharacterBufferReference; @@ -155,7 +155,7 @@ namespace Avalonia.Media.TextFormatting return length > 0; } - internal SplitResult Split(int length) + internal SplitResult Split(int length) { if (IsReversed) { @@ -171,7 +171,7 @@ namespace Avalonia.Media.TextFormatting var splitBuffer = ShapedBuffer.Split(length); - var first = new ShapedTextCharacters(splitBuffer.First, Properties); + var first = new ShapedTextRun(splitBuffer.First, Properties); #if DEBUG @@ -182,9 +182,9 @@ namespace Avalonia.Media.TextFormatting #endif - var second = new ShapedTextCharacters(splitBuffer.Second!, Properties); + var second = new ShapedTextRun(splitBuffer.Second!, Properties); - return new SplitResult(first, second); + return new SplitResult(first, second); } internal GlyphRun CreateGlyphRun() diff --git a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs index 0be753bd04..db035b8750 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs @@ -91,12 +91,12 @@ namespace Avalonia.Media.TextFormatting public override TextRunProperties Properties { get; } /// - /// Gets a list of . + /// Gets a list of . /// /// The shapeable text characters. - internal IReadOnlyList GetShapeableCharacters(CharacterBufferRange characterBufferRange, sbyte biDiLevel, ref TextRunProperties? previousProperties) + internal IReadOnlyList GetShapeableCharacters(CharacterBufferRange characterBufferRange, sbyte biDiLevel, ref TextRunProperties? previousProperties) { - var shapeableCharacters = new List(2); + var shapeableCharacters = new List(2); while (characterBufferRange.Length > 0) { @@ -120,7 +120,7 @@ namespace Avalonia.Media.TextFormatting /// The bidi level of the run. /// /// A list of shapeable text runs. - private static ShapeableTextCharacters CreateShapeableRun(CharacterBufferRange characterBufferRange, + private static UnshapedTextRun CreateShapeableRun(CharacterBufferRange characterBufferRange, TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties? previousProperties) { var defaultTypeface = defaultProperties.Typeface; @@ -133,12 +133,12 @@ namespace Avalonia.Media.TextFormatting { 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); } } - return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface), + return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface), biDiLevel); } @@ -146,7 +146,7 @@ namespace Avalonia.Media.TextFormatting { 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); } } @@ -176,7 +176,7 @@ namespace Avalonia.Media.TextFormatting if (matchFound && TryGetShapeableLength(characterBufferRange, currentTypeface, defaultTypeface, out count, out _)) { //Fallback found - return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface), + return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties.WithTypeface(currentTypeface), biDiLevel); } @@ -199,7 +199,7 @@ namespace Avalonia.Media.TextFormatting count += grapheme.Text.Length; } - return new ShapeableTextCharacters(characterBufferRange.CharacterBufferReference, count, defaultProperties, biDiLevel); + return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties, biDiLevel); } /// diff --git a/src/Avalonia.Base/Media/TextFormatting/TextEllipsisHelper.cs b/src/Avalonia.Base/Media/TextFormatting/TextEllipsisHelper.cs index a1b8985b43..086ea85d97 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextEllipsisHelper.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextEllipsisHelper.cs @@ -31,7 +31,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { currentWidth += shapedRun.Size.Width; diff --git a/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs index 93eb4811b9..ef2abdfea0 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs @@ -124,7 +124,7 @@ namespace Avalonia.Media.TextFormatting var second = new List(secondCount); - if (currentRun is ShapedTextCharacters shapedTextCharacters) + if (currentRun is ShapedTextRun shapedTextCharacters) { var split = shapedTextCharacters.Split(length - currentLength); @@ -206,16 +206,16 @@ namespace Avalonia.Media.TextFormatting break; } - case ShapeableTextCharacters shapeableRun: + case UnshapedTextRun shapeableRun: { - var groupedRuns = new List(2) { shapeableRun }; + var groupedRuns = new List(2) { shapeableRun }; var characterBufferReference = currentRun.CharacterBufferReference; var length = currentRun.Length; var offsetToFirstCharacter = characterBufferReference.OffsetToFirstChar; while (index + 1 < processedRuns.Count) { - if (processedRuns[index + 1] is not ShapeableTextCharacters nextRun) + if (processedRuns[index + 1] is not UnshapedTextRun nextRun) { break; } @@ -258,10 +258,10 @@ namespace Avalonia.Media.TextFormatting return drawableTextRuns; } - private static IReadOnlyList ShapeTogether( - IReadOnlyList textRuns, CharacterBufferReference text, int length, TextShaperOptions options) + private static IReadOnlyList ShapeTogether( + IReadOnlyList textRuns, CharacterBufferReference text, int length, TextShaperOptions options) { - var shapedRuns = new List(textRuns.Count); + var shapedRuns = new List(textRuns.Count); var shapedBuffer = TextShaper.Current.ShapeText(text, length, options); @@ -271,7 +271,7 @@ namespace Avalonia.Media.TextFormatting 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!; } @@ -280,9 +280,9 @@ namespace Avalonia.Media.TextFormatting } /// - /// Coalesces ranges of the same bidi level to form + /// Coalesces ranges of the same bidi level to form /// - /// The text characters to form from. + /// The text characters to form from. /// The bidi levels. /// private static IEnumerable> CoalesceLevels(IReadOnlyList textCharacters, ArraySlice levels) @@ -474,7 +474,7 @@ namespace Avalonia.Media.TextFormatting { switch (currentRun) { - case ShapedTextCharacters shapedTextCharacters: + case ShapedTextRun shapedTextCharacters: { if(shapedTextCharacters.ShapedBuffer.Length > 0) { @@ -538,7 +538,7 @@ namespace Avalonia.Media.TextFormatting var shapedBuffer = new ShapedBuffer(characterBufferRange, glyphInfos, glyphTypeface, properties.FontRenderingEmSize, (sbyte)flowDirection); - var textRuns = new List { new ShapedTextCharacters(shapedBuffer, properties) }; + var textRuns = new List { new ShapedTextRun(shapedBuffer, properties) }; return new TextLineImpl(textRuns, firstTextSourceIndex, 0, paragraphWidth, paragraphProperties, flowDirection).FinalizeLine(); } @@ -744,7 +744,7 @@ namespace Avalonia.Media.TextFormatting /// /// The shaped symbol. /// - internal static ShapedTextCharacters CreateSymbol(TextRun textRun, FlowDirection flowDirection) + internal static ShapedTextRun CreateSymbol(TextRun textRun, FlowDirection flowDirection) { var textShaper = TextShaper.Current; @@ -760,7 +760,7 @@ namespace Avalonia.Media.TextFormatting var shapedBuffer = textShaper.ShapeText(characterBuffer, textRun.Length, shaperOptions); - return new ShapedTextCharacters(shapedBuffer, textRun.Properties); + return new ShapedTextRun(shapedBuffer, textRun.Properties); } } } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs b/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs index 2752af8f0c..7b80d5ce40 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs @@ -65,7 +65,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { currentWidth += currentRun.Size.Width; @@ -118,7 +118,7 @@ namespace Avalonia.Media.TextFormatting switch (run) { - case ShapedTextCharacters endShapedRun: + case ShapedTextRun endShapedRun: { if (endShapedRun.TryMeasureCharactersBackwards(availableSuffixWidth, out var suffixCount, out var suffixWidth)) diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index d893468052..5fb1171221 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -192,14 +192,14 @@ namespace Avalonia.Media.TextFormatting { var currentRun = _textRuns[i]; - if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) + if (currentRun is ShapedTextRun shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) { var rightToLeftIndex = i; currentPosition += currentRun.Length; while (rightToLeftIndex + 1 <= _textRuns.Count - 1) { - var nextShaped = _textRuns[++rightToLeftIndex] as ShapedTextCharacters; + var nextShaped = _textRuns[++rightToLeftIndex] as ShapedTextRun; if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight) { @@ -255,7 +255,7 @@ namespace Avalonia.Media.TextFormatting switch (run) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); @@ -303,7 +303,7 @@ namespace Avalonia.Media.TextFormatting { var currentRun = _textRuns[index]; - if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) + if (currentRun is ShapedTextRun shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) { var i = index; @@ -313,7 +313,7 @@ namespace Avalonia.Media.TextFormatting { var nextRun = _textRuns[i + 1]; - if (nextRun is ShapedTextCharacters nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight) + if (nextRun is ShapedTextRun nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight) { i++; @@ -407,7 +407,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedTextCharacters: + case ShapedTextRun shapedTextCharacters: { currentGlyphRun = shapedTextCharacters.GlyphRun; @@ -476,7 +476,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { nextCharacterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(characterHit); break; @@ -550,7 +550,7 @@ namespace Avalonia.Media.TextFormatting double combinedWidth; - if (currentRun is ShapedTextCharacters currentShapedRun) + if (currentRun is ShapedTextRun currentShapedRun) { var firstCluster = currentShapedRun.GlyphRun.Metrics.FirstCluster; @@ -592,7 +592,7 @@ namespace Avalonia.Media.TextFormatting var rightToLeftIndex = index; 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) { @@ -624,12 +624,12 @@ namespace Avalonia.Media.TextFormatting for (int i = rightToLeftIndex - 1; i >= index; i--) { - if (TextRuns[i] is not ShapedTextCharacters) + if (TextRuns[i] is not ShapedTextRun) { continue; } - currentShapedRun = (ShapedTextCharacters)TextRuns[i]; + currentShapedRun = (ShapedTextRun)TextRuns[i]; currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength); @@ -769,7 +769,7 @@ namespace Avalonia.Media.TextFormatting var characterLength = 0; var endX = startX; - if (currentRun is ShapedTextCharacters currentShapedRun) + if (currentRun is ShapedTextRun currentShapedRun) { var offset = Math.Max(0, firstTextSourceIndex - currentPosition); @@ -883,7 +883,7 @@ namespace Avalonia.Media.TextFormatting 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; @@ -945,7 +945,7 @@ namespace Avalonia.Media.TextFormatting private static sbyte GetRunBidiLevel(DrawableTextRun run, FlowDirection flowDirection) { - if (run is ShapedTextCharacters shapedTextCharacters) + if (run is ShapedTextRun shapedTextCharacters) { return shapedTextCharacters.BidiLevel; } @@ -1027,7 +1027,7 @@ namespace Avalonia.Media.TextFormatting { 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(); } @@ -1145,7 +1145,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _); @@ -1230,7 +1230,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { var foundCharacterHit = shapedRun.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _); @@ -1294,7 +1294,7 @@ namespace Avalonia.Media.TextFormatting switch (currentRun) { - case ShapedTextCharacters shapedRun: + case ShapedTextRun shapedRun: { var firstCluster = shapedRun.GlyphRun.Metrics.FirstCluster; @@ -1303,7 +1303,7 @@ namespace Avalonia.Media.TextFormatting break; } - if (previousRun is ShapedTextCharacters previousShaped && !previousShaped.ShapedBuffer.IsLeftToRight) + if (previousRun is ShapedTextRun previousShaped && !previousShaped.ShapedBuffer.IsLeftToRight) { if (shapedRun.ShapedBuffer.IsLeftToRight) { @@ -1394,7 +1394,7 @@ namespace Avalonia.Media.TextFormatting { switch (_textRuns[index]) { - case ShapedTextCharacters textRun: + case ShapedTextRun textRun: { var textMetrics = new TextMetrics(textRun.Properties.Typeface.GlyphTypeface, textRun.Properties.FontRenderingEmSize); diff --git a/src/Avalonia.Base/Media/TextFormatting/ShapeableTextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/UnshapedTextRun.cs similarity index 61% rename from src/Avalonia.Base/Media/TextFormatting/ShapeableTextCharacters.cs rename to src/Avalonia.Base/Media/TextFormatting/UnshapedTextRun.cs index 0e8d6e3e4a..817086db88 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ShapeableTextCharacters.cs +++ b/src/Avalonia.Base/Media/TextFormatting/UnshapedTextRun.cs @@ -5,9 +5,9 @@ namespace Avalonia.Media.TextFormatting /// /// A group of characters that can be shaped. /// - 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) { CharacterBufferReference = characterBufferReference; @@ -24,30 +24,30 @@ namespace Avalonia.Media.TextFormatting 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; } - if (BidiLevel != shapeableTextCharacters.BidiLevel) + if (BidiLevel != unshapedTextRun.BidiLevel) { return false; } if (!MathUtilities.AreClose(Properties.FontRenderingEmSize, - shapeableTextCharacters.Properties.FontRenderingEmSize)) + unshapedTextRun.Properties.FontRenderingEmSize)) { return false; } - if (Properties.Typeface != shapeableTextCharacters.Properties.Typeface) + if (Properties.Typeface != unshapedTextRun.Properties.Typeface) { return false; } - if (Properties.BaselineAlignment != shapeableTextCharacters.Properties.BaselineAlignment) + if (Properties.BaselineAlignment != unshapedTextRun.Properties.BaselineAlignment) { return false; } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 33d4fba5f1..7fc27b01f4 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/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), 0, double.PositiveInfinity, paragraphProperties); - var expectedRuns = expectedTextLine.TextRuns.Cast().ToList(); + var expectedRuns = expectedTextLine.TextRuns.Cast().ToList(); var expectedGlyphs = expectedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList(); @@ -539,7 +539,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var textLine = formatter.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties); - var shapedRuns = textLine.TextRuns.Cast().ToList(); + var shapedRuns = textLine.TextRuns.Cast().ToList(); var actualGlyphs = shapedRuns.SelectMany(x => x.GlyphRun.GlyphIndices).ToList(); diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs index a407b38eb1..2790bd6096 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs @@ -141,7 +141,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting black, textWrapping: TextWrapping.Wrap); - var expectedGlyphs = expected.TextLines.Select(x => string.Join('|', x.TextRuns.Cast() + var expectedGlyphs = expected.TextLines.Select(x => string.Join('|', x.TextRuns.Cast() .SelectMany(x => x.ShapedBuffer.GlyphIndices))).ToList(); var outer = new GraphemeEnumerator(new CharacterBufferRange(text)); @@ -174,7 +174,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting textWrapping: TextWrapping.Wrap, textStyleOverrides: spans); - var actualGlyphs = actual.TextLines.Select(x => string.Join('|', x.TextRuns.Cast() + var actualGlyphs = actual.TextLines.Select(x => string.Join('|', x.TextRuns.Cast() .SelectMany(x => x.ShapedBuffer.GlyphIndices))).ToList(); Assert.Equal(expectedGlyphs.Count, actualGlyphs.Count); @@ -447,7 +447,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting 12.0f, Brushes.Black.ToImmutable()); - var shapedRun = (ShapedTextCharacters)layout.TextLines[0].TextRuns[0]; + var shapedRun = (ShapedTextRun)layout.TextLines[0].TextRuns[0]; var glyphRun = shapedRun.GlyphRun; @@ -481,7 +481,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting foreach (var textRun in textLine.TextRuns) { - var shapedRun = (ShapedTextCharacters)textRun; + var shapedRun = (ShapedTextRun)textRun; 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(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) { - 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 textRun = (ShapedTextCharacters)textLine.TextRuns[0]; + var textRun = (ShapedTextRun)textLine.TextRuns[0]; Assert.Equal(7, textRun.Length); @@ -775,7 +775,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Assert.Equal(textLine.WidthIncludingTrailingWhitespace, rect.Width); } - var rects = layout.TextLines.SelectMany(x => x.TextRuns.Cast()) + var rects = layout.TextLines.SelectMany(x => x.TextRuns.Cast()) .SelectMany(x => x.ShapedBuffer.GlyphAdvances).ToArray(); for (var i = 0; i < SingleLineText.Length; i++) @@ -814,7 +814,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting { Assert.True(textLine.Width <= maxWidth); - var actual = new string(textLine.TextRuns.Cast() + var actual = new string(textLine.TextRuns.Cast() .OrderBy(x => x.CharacterBufferReference.OffsetToFirstChar) .SelectMany(x => new CharacterBufferRange(x.CharacterBufferReference, x.Length)).ToArray()); @@ -855,7 +855,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Brushes.Black, 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()); @@ -881,7 +881,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting 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)); @@ -928,7 +928,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var textLine = layout.TextLines[0]; - var firstRun = (ShapedTextCharacters)textLine.TextRuns[0]; + var firstRun = (ShapedTextRun)textLine.TextRuns[0]; var firstCluster = firstRun.ShapedBuffer.GlyphClusters[0]; @@ -987,7 +987,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var textLine = layout.TextLines[0]; - var shapedRuns = textLine.TextRuns.Cast().ToList(); + var shapedRuns = textLine.TextRuns.Cast().ToList(); var clusters = shapedRuns.SelectMany(x => x.ShapedBuffer.GlyphClusters).ToList(); diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index d6257a0de8..ac2467407b 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/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)) { - var shapedRun = (ShapedTextCharacters)textRun; + var shapedRun = (ShapedTextRun)textRun; clusters.AddRange(shapedRun.IsReversed ? 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)) { - var shapedRun = (ShapedTextCharacters)textRun; + var shapedRun = (ShapedTextRun)textRun; clusters.AddRange(shapedRun.IsReversed ? shapedRun.ShapedBuffer.GlyphClusters.Reverse() : @@ -246,7 +246,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting formatter.FormatLine(textSource, 0, double.PositiveInfinity, new GenericTextParagraphProperties(defaultProperties)); - var clusters = textLine.TextRuns.Cast().SelectMany(x => x.ShapedBuffer.GlyphClusters) + var clusters = textLine.TextRuns.Cast().SelectMany(x => x.ShapedBuffer.GlyphClusters) .ToArray(); var previousCharacterHit = new CharacterHit(text.Length); @@ -308,7 +308,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting foreach (var run in textLine.TextRuns) { - var textRun = (ShapedTextCharacters)run; + var textRun = (ShapedTextRun)run; var glyphRun = textRun.GlyphRun; @@ -634,7 +634,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting formatter.FormatLine(textSource, 0, double.PositiveInfinity, new GenericTextParagraphProperties(defaultProperties)); - var textRuns = textLine.TextRuns.Cast().ToList(); + var textRuns = textLine.TextRuns.Cast().ToList(); var lineWidth = textLine.WidthIncludingTrailingWhitespace; @@ -732,14 +732,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting private static bool IsRightToLeft(TextLine textLine) { - return textLine.TextRuns.Cast().Any(x => !x.ShapedBuffer.IsLeftToRight); + return textLine.TextRuns.Cast().Any(x => !x.ShapedBuffer.IsLeftToRight); } private static List BuildGlyphClusters(TextLine textLine) { var glyphClusters = new List(); - var shapedTextRuns = textLine.TextRuns.Cast().ToList(); + var shapedTextRuns = textLine.TextRuns.Cast().ToList(); var lastCluster = -1; @@ -774,7 +774,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var lastCluster = -1; - var shapedTextRuns = textLine.TextRuns.Cast().ToList(); + var shapedTextRuns = textLine.TextRuns.Cast().ToList(); foreach (var textRun in shapedTextRuns) { @@ -820,16 +820,16 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var text = "0123"; 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 { new CustomDrawableRun(), firstRun, new CustomDrawableRun(), - new ShapedTextCharacters(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties), + new ShapedTextRun(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties), new CustomDrawableRun(), - new ShapedTextCharacters(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties) + new ShapedTextRun(TextShaper.Current.ShapeText(text, shaperOption), defaultProperties) }; var textSource = new FixedRunsTextSource(textRuns); @@ -885,14 +885,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting 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(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); 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(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 secondRun = textLine.TextRuns[1] as ShapedTextCharacters; + var secondRun = textLine.TextRuns[1] as ShapedTextRun; Assert.Equal(1, textBounds.Count); Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); textBounds = textLine.GetTextBounds(4, 3); - var firstRun = textLine.TextRuns[0] as ShapedTextCharacters; + var firstRun = textLine.TextRuns[0] as ShapedTextRun; Assert.Equal(1, textBounds.Count); From 490c9b1ffe6a69037dee03b723bc1ba80b0ba0b2 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Fri, 6 Jan 2023 00:58:20 +0300 Subject: [PATCH 04/30] [Text] fix tab width. It's too long --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 2 +- .../Media/TextFormatting/TextParagraphProperties.cs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 6a4d9b7d0e..7408399873 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -38,7 +38,7 @@ UseFloatingWatermark="True" PasswordChar="*" Text="Password" /> - + /// Gets the default incremental tab width. /// - public virtual double DefaultIncrementalTab - { - get { return 4 * DefaultTextRunProperties.FontRenderingEmSize; } - } + public virtual double DefaultIncrementalTab => 0; /// /// Gets the letter spacing. From fb37ab1e7725deef8b54a69d21a17f92ba361c8d Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 10:46:29 +1100 Subject: [PATCH 05/30] leverage GetRequiredService --- samples/ControlCatalog.Desktop/Program.cs | 2 +- samples/ControlCatalog/Pages/TabControlPage.xaml.cs | 2 +- .../ViewModels/CursorPageViewModel.cs | 2 +- .../TransitioningContentControlPageViewModel.cs | 2 +- src/Avalonia.Base/Input/Cursor.cs | 3 +-- src/Avalonia.Base/Media/FontManager.cs | 5 +---- .../Media/TextFormatting/TextShaper.cs | 5 +---- src/Avalonia.Base/Rendering/RenderLoop.cs | 3 +-- src/Avalonia.Base/Threading/DispatcherTimer.cs | 8 +------- src/Avalonia.Controls/Platform/PlatformManager.cs | 13 +++---------- src/Avalonia.DesignerSupport/DesignWindowLoader.cs | 5 +---- .../Internal/ManagedFileChooserViewModel.cs | 2 +- src/Avalonia.OpenGL/Egl/EglInterface.cs | 2 +- src/Avalonia.X11/X11Framebuffer.cs | 2 +- src/Avalonia.X11/X11Platform.cs | 2 +- .../Converters/BitmapTypeConverter.cs | 2 +- .../Converters/IconTypeConverter.cs | 2 +- src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs | 2 +- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 6 +++--- .../Media/DWriteResourceFontLoader.cs | 2 +- .../Avalonia.Direct2D1/Media/DrawingContextImpl.cs | 2 +- .../Wpf/Direct2DImageSurface.cs | 2 +- .../Media/Fonts/FontFamilyLoaderTests.cs | 2 +- .../Avalonia.Controls.UnitTests/ContextMenuTests.cs | 2 +- tests/Avalonia.Controls.UnitTests/FlyoutTests.cs | 2 +- .../MaskedTextBoxTests.cs | 2 +- .../Primitives/PopupTests.cs | 2 +- tests/Avalonia.Controls.UnitTests/TextBoxTests.cs | 4 ++-- tests/Avalonia.Controls.UnitTests/TreeViewTests.cs | 9 ++++----- .../AutoSuspendHelperTest.cs | 6 +++--- tests/Avalonia.RenderTests/TestBase.cs | 2 +- tests/Avalonia.UnitTests/HarfBuzzFontManagerImpl.cs | 7 +------ 32 files changed, 42 insertions(+), 72 deletions(-) diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index 7b8b27fff7..4d28f15e2c 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -23,7 +23,7 @@ namespace ControlCatalog private static void ConfigureAssetAssembly(AppBuilder builder) { AvaloniaLocator.CurrentMutable - .GetService() + .GetRequiredService() .SetDefaultAssembly(typeof(App).Assembly); } } diff --git a/samples/ControlCatalog/Pages/TabControlPage.xaml.cs b/samples/ControlCatalog/Pages/TabControlPage.xaml.cs index 413b6e1c75..f3f4bf6e93 100644 --- a/samples/ControlCatalog/Pages/TabControlPage.xaml.cs +++ b/samples/ControlCatalog/Pages/TabControlPage.xaml.cs @@ -51,7 +51,7 @@ namespace ControlCatalog.Pages private static IBitmap LoadBitmap(string uri) { - var assets = AvaloniaLocator.Current!.GetService()!; + var assets = AvaloniaLocator.Current.GetRequiredService(); return new Bitmap(assets.Open(new Uri(uri))); } } diff --git a/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs b/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs index 8a3f0ba947..12ca6af4f5 100644 --- a/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs @@ -18,7 +18,7 @@ namespace ControlCatalog.ViewModels .Select(x => new StandardCursorModel(x)) .ToList(); - var loader = AvaloniaLocator.Current!.GetService()!; + var loader = AvaloniaLocator.Current.GetRequiredService()!; var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png")); var bitmap = new Bitmap(s); CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16)); diff --git a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs index 93857fd899..f4e0bc8912 100644 --- a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs @@ -19,7 +19,7 @@ namespace ControlCatalog.ViewModels { public TransitioningContentControlPageViewModel() { - var assetLoader = AvaloniaLocator.Current?.GetService()!; + var assetLoader = AvaloniaLocator.Current.GetRequiredService()!; var images = new string[] { diff --git a/src/Avalonia.Base/Input/Cursor.cs b/src/Avalonia.Base/Input/Cursor.cs index 8e79206f93..c555087879 100644 --- a/src/Avalonia.Base/Input/Cursor.cs +++ b/src/Avalonia.Base/Input/Cursor.cs @@ -71,8 +71,7 @@ namespace Avalonia.Input private static ICursorFactory GetCursorFactory() { - return AvaloniaLocator.Current.GetService() ?? - throw new Exception("Could not create Cursor: ICursorFactory not registered."); + return AvaloniaLocator.Current.GetRequiredService(); } } } diff --git a/src/Avalonia.Base/Media/FontManager.cs b/src/Avalonia.Base/Media/FontManager.cs index d92d003c2a..e82d5b7ba5 100644 --- a/src/Avalonia.Base/Media/FontManager.cs +++ b/src/Avalonia.Base/Media/FontManager.cs @@ -47,10 +47,7 @@ namespace Avalonia.Media return current; } - var fontManagerImpl = AvaloniaLocator.Current.GetService(); - - if (fontManagerImpl == null) - throw new InvalidOperationException("No font manager implementation was registered."); + var fontManagerImpl = AvaloniaLocator.Current.GetRequiredService(); current = new FontManager(fontManagerImpl); diff --git a/src/Avalonia.Base/Media/TextFormatting/TextShaper.cs b/src/Avalonia.Base/Media/TextFormatting/TextShaper.cs index 4aacec7c48..c161b08d20 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextShaper.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextShaper.cs @@ -29,10 +29,7 @@ namespace Avalonia.Media.TextFormatting return current; } - var textShaperImpl = AvaloniaLocator.Current.GetService(); - - if (textShaperImpl == null) - throw new InvalidOperationException("No text shaper implementation was registered."); + var textShaperImpl = AvaloniaLocator.Current.GetRequiredService(); current = new TextShaper(textShaperImpl); diff --git a/src/Avalonia.Base/Rendering/RenderLoop.cs b/src/Avalonia.Base/Rendering/RenderLoop.cs index 5a08bfc6a1..1f58ca3827 100644 --- a/src/Avalonia.Base/Rendering/RenderLoop.cs +++ b/src/Avalonia.Base/Rendering/RenderLoop.cs @@ -50,8 +50,7 @@ namespace Avalonia.Rendering { get { - return _timer ??= AvaloniaLocator.Current.GetService() ?? - throw new InvalidOperationException("Cannot locate IRenderTimer."); + return _timer ??= AvaloniaLocator.Current.GetRequiredService(); } } diff --git a/src/Avalonia.Base/Threading/DispatcherTimer.cs b/src/Avalonia.Base/Threading/DispatcherTimer.cs index 0c25d89722..8fc91a02d8 100644 --- a/src/Avalonia.Base/Threading/DispatcherTimer.cs +++ b/src/Avalonia.Base/Threading/DispatcherTimer.cs @@ -176,13 +176,7 @@ namespace Avalonia.Threading { if (!IsEnabled) { - var threading = AvaloniaLocator.Current.GetService(); - - if (threading == null) - { - throw new Exception("Could not start timer: IPlatformThreadingInterface is not registered."); - } - + var threading = AvaloniaLocator.Current.GetRequiredService(); _timer = threading.StartTimer(_priority, Interval, InternalTick); } } diff --git a/src/Avalonia.Controls/Platform/PlatformManager.cs b/src/Avalonia.Controls/Platform/PlatformManager.cs index de7708e869..b01fc28831 100644 --- a/src/Avalonia.Controls/Platform/PlatformManager.cs +++ b/src/Avalonia.Controls/Platform/PlatformManager.cs @@ -21,26 +21,19 @@ namespace Avalonia.Controls.Platform } public static ITrayIconImpl? CreateTrayIcon() => - s_designerMode ? null : AvaloniaLocator.Current.GetService()?.CreateTrayIcon(); + s_designerMode ? null : AvaloniaLocator.Current.GetRequiredService().CreateTrayIcon(); public static IWindowImpl CreateWindow() { - var platform = AvaloniaLocator.Current.GetService(); - - if (platform == null) - { - throw new Exception("Could not CreateWindow(): IWindowingPlatform is not registered."); - } + var platform = AvaloniaLocator.Current.GetRequiredService(); return s_designerMode ? platform.CreateEmbeddableWindow() : platform.CreateWindow(); } public static IWindowImpl CreateEmbeddableWindow() { - var platform = AvaloniaLocator.Current.GetService(); - if (platform == null) - throw new Exception("Could not CreateEmbeddableWindow(): IWindowingPlatform is not registered."); + var platform = AvaloniaLocator.Current.GetRequiredService(); return platform.CreateEmbeddableWindow(); } } diff --git a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs index b4cfffcdca..eff190c39e 100644 --- a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs +++ b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs @@ -18,12 +18,9 @@ namespace Avalonia.DesignerSupport Control control; using (PlatformManager.DesignerMode()) { - var loader = AvaloniaLocator.Current.GetService(); + var loader = AvaloniaLocator.Current.GetRequiredService(); var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)); - if (loader == null) - throw new XamlLoadException("Runtime XAML loader is not registered"); - Uri baseUri = null; if (assemblyPath != null) { diff --git a/src/Avalonia.Dialogs/Internal/ManagedFileChooserViewModel.cs b/src/Avalonia.Dialogs/Internal/ManagedFileChooserViewModel.cs index 7d0072c6ea..3de79927b2 100644 --- a/src/Avalonia.Dialogs/Internal/ManagedFileChooserViewModel.cs +++ b/src/Avalonia.Dialogs/Internal/ManagedFileChooserViewModel.cs @@ -117,7 +117,7 @@ namespace Avalonia.Dialogs.Internal ?? new ManagedFileChooserSources(); var sub1 = AvaloniaLocator.Current - .GetService() + .GetRequiredService() .Listen(ManagedFileChooserSources.MountedVolumes); var sub2 = Observable.FromEventPattern(ManagedFileChooserSources.MountedVolumes, diff --git a/src/Avalonia.OpenGL/Egl/EglInterface.cs b/src/Avalonia.OpenGL/Egl/EglInterface.cs index a913c05996..06aafb4f57 100644 --- a/src/Avalonia.OpenGL/Egl/EglInterface.cs +++ b/src/Avalonia.OpenGL/Egl/EglInterface.cs @@ -35,7 +35,7 @@ namespace Avalonia.OpenGL.Egl static Func Load(string library) { - var dyn = AvaloniaLocator.Current.GetService(); + var dyn = AvaloniaLocator.Current.GetRequiredService(); var lib = dyn.LoadLibrary(library); return (s) => dyn.GetProcAddress(lib, s, true); } diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs index 94f930e9ec..a9fedff8b5 100644 --- a/src/Avalonia.X11/X11Framebuffer.cs +++ b/src/Avalonia.X11/X11Framebuffer.cs @@ -25,7 +25,7 @@ namespace Avalonia.X11 RowBytes = width * 4; Dpi = new Vector(96, 96) * factor; Format = PixelFormat.Bgra8888; - _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * height); + _blob = AvaloniaLocator.Current.GetRequiredService().AllocBlob(RowBytes * height); Address = _blob.Address; } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 9692e0a384..0f9ef72a3f 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -105,7 +105,7 @@ namespace Avalonia.X11 var gl = AvaloniaLocator.Current.GetService(); if (options.UseCompositor) - Compositor = new Compositor(AvaloniaLocator.Current.GetService()!, gl); + Compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService(), gl); else RenderInterface = new(gl); diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs index dcd60f7a79..fc6a8557f3 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs @@ -24,7 +24,7 @@ namespace Avalonia.Markup.Xaml.Converters if(uri.IsAbsoluteUri && uri.IsFile) return new Bitmap(uri.LocalPath); - var assets = AvaloniaLocator.Current.GetService(); + var assets = AvaloniaLocator.Current.GetRequiredService(); return new Bitmap(assets.Open(uri, context.GetContextBaseUri())); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs index 24b690b6f1..698f5a9327 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs @@ -40,7 +40,7 @@ namespace Avalonia.Markup.Xaml.Converters if(uri.IsAbsoluteUri && uri.IsFile) return new WindowIcon(uri.LocalPath); - var assets = AvaloniaLocator.Current.GetService(); + var assets = AvaloniaLocator.Current.GetRequiredService(); return new WindowIcon(assets.Open(uri, context.GetContextBaseUri())); } } diff --git a/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs b/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs index 5ca7f40d17..f7a86c11ff 100644 --- a/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs +++ b/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs @@ -37,7 +37,7 @@ namespace Avalonia.Skia var typeFaceCollection = new SKTypefaceCollection(); - var assetLoader = AvaloniaLocator.Current.GetService(); + var assetLoader = AvaloniaLocator.Current.GetRequiredService(); foreach (var asset in fontAssets) { diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index dcb267b2a3..12d9471204 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -96,9 +96,9 @@ namespace Avalonia.Skia SKColorType colorType = format.ToSkColorType(); SKAlphaType alphaType = alphaFormat.ToSkAlphaType(); - - var runtimePlatform = AvaloniaLocator.Current?.GetService(); - + + var runtimePlatform = AvaloniaLocator.Current.GetRequiredService(); + if (runtimePlatform != null) { _bitmap = new SKBitmap(); diff --git a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs index e5f87e71a2..4663a6561f 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontLoader.cs @@ -22,7 +22,7 @@ namespace Avalonia.Direct2D1.Media { var factory1 = factory; - var assetLoader = AvaloniaLocator.Current.GetService(); + var assetLoader = AvaloniaLocator.Current.GetRequiredService(); foreach (var asset in fontAssets) { diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 180ae491b3..3f2298eb22 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -409,7 +409,7 @@ namespace Avalonia.Direct2D1.Media } else { - var platform = AvaloniaLocator.Current.GetService(); + var platform = AvaloniaLocator.Current.GetRequiredService(); var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height); var pixelSize = PixelSize.FromSizeWithDpi(size, dpi); return (IDrawingContextLayerImpl)platform.CreateRenderTargetBitmap(pixelSize, dpi); diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs index a5474803a1..e607e255a5 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs @@ -127,7 +127,7 @@ namespace Avalonia.Win32.Interop.Wpf DeviceWindowHandle = GetDesktopWindow(), PresentationInterval = PresentInterval.Default }; - s_dxDevice = s_dxDevice ?? AvaloniaLocator.Current.GetService() + s_dxDevice = s_dxDevice ?? AvaloniaLocator.Current.GetRequiredService() .QueryInterface(); s_d3DDevice = new DeviceEx(s_d3DContext, 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, presentparams); diff --git a/tests/Avalonia.Base.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs b/tests/Avalonia.Base.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs index aa042ffec8..afc25ab88e 100644 --- a/tests/Avalonia.Base.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs @@ -97,7 +97,7 @@ namespace Avalonia.Base.UnitTests.Media.Fonts { using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) { - var assetLoader = AvaloniaLocator.Current.GetService(); + var assetLoader = AvaloniaLocator.Current.GetRequiredService(); var fontFamily = new FontFamily("resm:Avalonia.Base.UnitTests.Assets?assembly=Avalonia.Base.UnitTests#Noto Mono"); diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs index d6c521decd..baf933bd66 100644 --- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs @@ -596,7 +596,7 @@ namespace Avalonia.Controls.UnitTests private static Window PreparedWindow(object content = null) { var renderer = new Mock(); - var platform = AvaloniaLocator.Current.GetService(); + var platform = AvaloniaLocator.Current.GetRequiredService(); var windowImpl = Mock.Get(platform.CreateWindow()); windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); diff --git a/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs b/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs index 496b5bc1b6..02767a21eb 100644 --- a/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs +++ b/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs @@ -570,7 +570,7 @@ namespace Avalonia.Controls.UnitTests private static Window PreparedWindow(object content = null) { var renderer = new Mock(); - var platform = AvaloniaLocator.Current.GetService(); + var platform = AvaloniaLocator.Current.GetRequiredService(); var windowImpl = Mock.Get(platform.CreateWindow()); windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); diff --git a/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs index 90c6fd3b21..c1d9fad6f4 100644 --- a/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs @@ -827,7 +827,7 @@ namespace Avalonia.Controls.UnitTests { AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); - var clipboard = AvaloniaLocator.CurrentMutable.GetService(); + var clipboard = AvaloniaLocator.CurrentMutable.GetRequiredService(); clipboard.SetTextAsync(textInput).GetAwaiter().GetResult(); RaiseKeyEvent(target, Key.V, KeyModifiers.Control); diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index d4193d33ee..65957fda6d 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -564,7 +564,7 @@ namespace Avalonia.Controls.UnitTests.Primitives using (CreateServices()) { var renderer = new Mock(); - var platform = AvaloniaLocator.Current.GetService(); + var platform = AvaloniaLocator.Current.GetRequiredService(); var windowImpl = Mock.Get(platform.CreateWindow()); windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index bd6d5d55e2..531a2869cd 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -767,7 +767,7 @@ namespace Avalonia.Controls.UnitTests { AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); - var clipboard = AvaloniaLocator.CurrentMutable.GetService(); + var clipboard = AvaloniaLocator.CurrentMutable.GetRequiredService(); clipboard.SetTextAsync(textInput).GetAwaiter().GetResult(); RaiseKeyEvent(target, Key.V, KeyModifiers.Control); @@ -876,7 +876,7 @@ namespace Avalonia.Controls.UnitTests AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); - var clipboard = AvaloniaLocator.CurrentMutable.GetService(); + var clipboard = AvaloniaLocator.CurrentMutable.GetRequiredService(); clipboard.SetTextAsync(Environment.NewLine).GetAwaiter().GetResult(); RaiseKeyEvent(target, Key.V, KeyModifiers.Control); diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index 81936711ef..f526465b9b 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -1248,7 +1248,7 @@ namespace Avalonia.Controls.UnitTests using (Application()) { var focus = FocusManager.Instance; - var navigation = AvaloniaLocator.Current.GetService(); + var navigation = AvaloniaLocator.Current.GetRequiredService(); var data = CreateTestTreeData(); var target = new TreeView @@ -1293,7 +1293,6 @@ namespace Avalonia.Controls.UnitTests using (Application()) { var focus = FocusManager.Instance; - var navigation = AvaloniaLocator.Current.GetService(); var data = CreateTestTreeData(); var selectedNode = new Node { Value = "Out of Tree Selected Item" }; @@ -1353,7 +1352,7 @@ namespace Avalonia.Controls.UnitTests var rootNode = tree[0]; - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = AvaloniaLocator.Current.GetRequiredService(); var selectAllGesture = keymap.SelectAll.First(); var keyEvent = new KeyEventArgs @@ -1400,7 +1399,7 @@ namespace Avalonia.Controls.UnitTests ClickContainer(fromContainer, KeyModifiers.None); ClickContainer(toContainer, KeyModifiers.Shift); - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = AvaloniaLocator.Current.GetRequiredService(); var selectAllGesture = keymap.SelectAll.First(); var keyEvent = new KeyEventArgs @@ -1447,7 +1446,7 @@ namespace Avalonia.Controls.UnitTests ClickContainer(fromContainer, KeyModifiers.None); ClickContainer(toContainer, KeyModifiers.Shift); - var keymap = AvaloniaLocator.Current.GetService(); + var keymap = AvaloniaLocator.Current.GetRequiredService(); var selectAllGesture = keymap.SelectAll.First(); var keyEvent = new KeyEventArgs diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs index 196375fb40..30326adba5 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs @@ -47,7 +47,7 @@ namespace Avalonia.ReactiveUI.UnitTests using (var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var isLaunchingReceived = false; - var application = AvaloniaLocator.Current.GetService(); + var application = AvaloniaLocator.Current.GetRequiredService(); application.ApplicationLifetime = lifetime; // Initialize ReactiveUI Suspension as in real-world scenario. @@ -65,7 +65,7 @@ namespace Avalonia.ReactiveUI.UnitTests using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) using (var lifetime = new ExoticApplicationLifetimeWithoutLifecycleEvents()) { - var application = AvaloniaLocator.Current.GetService(); + var application = AvaloniaLocator.Current.GetRequiredService(); application.ApplicationLifetime = lifetime; Assert.Throws(() => new AutoSuspendHelper(application.ApplicationLifetime)); } @@ -88,7 +88,7 @@ namespace Avalonia.ReactiveUI.UnitTests using (var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var shouldPersistReceived = false; - var application = AvaloniaLocator.Current.GetService(); + var application = AvaloniaLocator.Current.GetRequiredService(); application.ApplicationLifetime = lifetime; // Initialize ReactiveUI Suspension as in real-world scenario. diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index 313281d6c6..edde62f041 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -91,7 +91,7 @@ namespace Avalonia.Direct2D1.RenderTests var immediatePath = Path.Combine(OutputPath, testName + ".immediate.out.png"); var deferredPath = Path.Combine(OutputPath, testName + ".deferred.out.png"); var compositedPath = Path.Combine(OutputPath, testName + ".composited.out.png"); - var factory = AvaloniaLocator.Current.GetService(); + var factory = AvaloniaLocator.Current.GetRequiredService(); var pixelSize = new PixelSize((int)target.Width, (int)target.Height); var size = new Size(target.Width, target.Height); var dpiVector = new Vector(dpi, dpi); diff --git a/tests/Avalonia.UnitTests/HarfBuzzFontManagerImpl.cs b/tests/Avalonia.UnitTests/HarfBuzzFontManagerImpl.cs index 2b1685f358..55ac16054d 100644 --- a/tests/Avalonia.UnitTests/HarfBuzzFontManagerImpl.cs +++ b/tests/Avalonia.UnitTests/HarfBuzzFontManagerImpl.cs @@ -76,13 +76,8 @@ namespace Avalonia.UnitTests var asset = fontAssets.First(); - var assetLoader = AvaloniaLocator.Current.GetService(); + var assetLoader = AvaloniaLocator.Current.GetRequiredService(); - if (assetLoader == null) - { - throw new NotSupportedException("IAssetLoader is not registered."); - } - var stream = assetLoader.Open(asset); return new HarfBuzzGlyphTypefaceImpl(stream); From 698977d2836e41bc6bb4083f14bf1ced746bb2fb Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 10:47:27 +1100 Subject: [PATCH 06/30] . --- samples/ControlCatalog/ViewModels/CursorPageViewModel.cs | 2 +- .../ViewModels/TransitioningContentControlPageViewModel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs b/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs index 12ca6af4f5..f44d927801 100644 --- a/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/CursorPageViewModel.cs @@ -18,7 +18,7 @@ namespace ControlCatalog.ViewModels .Select(x => new StandardCursorModel(x)) .ToList(); - var loader = AvaloniaLocator.Current.GetRequiredService()!; + var loader = AvaloniaLocator.Current.GetRequiredService(); var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png")); var bitmap = new Bitmap(s); CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16)); diff --git a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs index f4e0bc8912..4505c11e95 100644 --- a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs @@ -19,7 +19,7 @@ namespace ControlCatalog.ViewModels { public TransitioningContentControlPageViewModel() { - var assetLoader = AvaloniaLocator.Current.GetRequiredService()!; + var assetLoader = AvaloniaLocator.Current.GetRequiredService(); var images = new string[] { From 16ffe2f6f99d41adab83e58b9f0f927daaf92bae Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 10:50:23 +1100 Subject: [PATCH 07/30] use default literal --- .../Data/Converters/FuncMultiValueConverter.cs | 2 +- src/Avalonia.Base/Layout/WrapLayout/UvMeasure.cs | 2 +- src/Avalonia.Base/Media/DrawingContext.cs | 2 +- src/Avalonia.Base/Media/DrawingGroup.cs | 4 ++-- src/Avalonia.Base/Media/ImmediateDrawingContext.cs | 2 +- .../Composition/Expressions/ExpressionVariant.cs | 2 +- src/Avalonia.Base/Rendering/ImmediateRenderer.cs | 6 +++--- .../Rendering/Utilities/TileBrushCalculator.cs | 2 +- src/Avalonia.Base/Utilities/SingleOrDictionary.cs | 2 +- src/Avalonia.Base/Utilities/StringTokenizer.cs | 4 ++-- src/Avalonia.Controls.DataGrid/DataGrid.cs | 4 ++-- src/Avalonia.Controls.DataGrid/IndexToValueTable.cs | 2 +- src/Avalonia.Controls/Platform/InProcessDragSource.cs | 2 +- .../Presenters/ScrollContentPresenter.cs | 4 ++-- src/Avalonia.Controls/Utils/UndoRedoHelper.cs | 2 +- src/Avalonia.FreeDesktop/DBusMenu.cs | 8 ++++---- .../Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs | 2 +- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 4 ++-- src/Skia/Avalonia.Skia/GeometryImpl.cs | 2 +- .../Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs | 4 ++-- src/Windows/Avalonia.Win32/DataObject.cs | 2 +- src/Windows/Avalonia.Win32/OleDropTarget.cs | 2 +- .../ItemsPresenterTests_Virtualization_Simple.cs | 2 +- 23 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs b/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs index 2577cac743..5084d8e822 100644 --- a/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs +++ b/src/Avalonia.Base/Data/Converters/FuncMultiValueConverter.cs @@ -38,7 +38,7 @@ namespace Avalonia.Data.Converters } else if (Equals(obj, default(TIn))) { - yield return default(TIn); + yield return default; } } } diff --git a/src/Avalonia.Base/Layout/WrapLayout/UvMeasure.cs b/src/Avalonia.Base/Layout/WrapLayout/UvMeasure.cs index 91fa459acb..fa298b53a3 100644 --- a/src/Avalonia.Base/Layout/WrapLayout/UvMeasure.cs +++ b/src/Avalonia.Base/Layout/WrapLayout/UvMeasure.cs @@ -7,7 +7,7 @@ namespace Avalonia.Layout { internal struct UvMeasure { - internal static readonly UvMeasure Zero = default(UvMeasure); + internal static readonly UvMeasure Zero = default; internal double U { get; set; } diff --git a/src/Avalonia.Base/Media/DrawingContext.cs b/src/Avalonia.Base/Media/DrawingContext.cs index eabd7c8274..077816c645 100644 --- a/src/Avalonia.Base/Media/DrawingContext.cs +++ b/src/Avalonia.Base/Media/DrawingContext.cs @@ -279,7 +279,7 @@ namespace Avalonia.Media OpacityMask, } - public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default(Matrix)) + public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default) { if (context._states is null) throw new ObjectDisposedException(nameof(DrawingContext)); diff --git a/src/Avalonia.Base/Media/DrawingGroup.cs b/src/Avalonia.Base/Media/DrawingGroup.cs index 4a46d89153..7d3b4c056e 100644 --- a/src/Avalonia.Base/Media/DrawingGroup.cs +++ b/src/Avalonia.Base/Media/DrawingGroup.cs @@ -76,8 +76,8 @@ namespace Avalonia.Media { using (context.PushPreTransform(Transform?.Value ?? Matrix.Identity)) using (context.PushOpacity(Opacity)) - using (ClipGeometry != null ? context.PushGeometryClip(ClipGeometry) : default(DrawingContext.PushedState)) - using (OpacityMask != null ? context.PushOpacityMask(OpacityMask, GetBounds()) : default(DrawingContext.PushedState)) + using (ClipGeometry != null ? context.PushGeometryClip(ClipGeometry) : default) + using (OpacityMask != null ? context.PushOpacityMask(OpacityMask, GetBounds()) : default) { foreach (var drawing in Children) { diff --git a/src/Avalonia.Base/Media/ImmediateDrawingContext.cs b/src/Avalonia.Base/Media/ImmediateDrawingContext.cs index 1e1a73437d..eb6f105680 100644 --- a/src/Avalonia.Base/Media/ImmediateDrawingContext.cs +++ b/src/Avalonia.Base/Media/ImmediateDrawingContext.cs @@ -218,7 +218,7 @@ namespace Avalonia.Media OpacityMask, } - internal PushedState(ImmediateDrawingContext context, PushedStateType type, Matrix matrix = default(Matrix)) + internal PushedState(ImmediateDrawingContext context, PushedStateType type, Matrix matrix = default) { if (context._states is null) throw new ObjectDisposedException(nameof(ImmediateDrawingContext)); diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs index 6e53a138cd..21f14283b5 100644 --- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs +++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs @@ -654,7 +654,7 @@ namespace Avalonia.Rendering.Composition.Expressions } } - res = default(T); + res = default; return false; } diff --git a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs index 4909c78ed1..60b144e806 100644 --- a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs @@ -330,11 +330,11 @@ namespace Avalonia.Rendering ? visual is IVisualWithRoundRectClip roundClipVisual ? context.PushClip(new RoundedRect(bounds, roundClipVisual.ClipToBoundsRadius)) : context.PushClip(bounds) - : default(DrawingContext.PushedState)) + : default) #pragma warning restore CS0618 // Type or member is obsolete - using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default(DrawingContext.PushedState)) - using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default(DrawingContext.PushedState)) + using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default) + using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default) using (context.PushTransformContainer()) { visual.Render(context); diff --git a/src/Avalonia.Base/Rendering/Utilities/TileBrushCalculator.cs b/src/Avalonia.Base/Rendering/Utilities/TileBrushCalculator.cs index af2c7f71dc..6b34b44337 100644 --- a/src/Avalonia.Base/Rendering/Utilities/TileBrushCalculator.cs +++ b/src/Avalonia.Base/Rendering/Utilities/TileBrushCalculator.cs @@ -109,7 +109,7 @@ namespace Avalonia.Rendering.Utilities { if (IntermediateTransform != Matrix.Identity) return true; - if (SourceRect.Position != default(Point)) + if (SourceRect.Position != default) return true; if (SourceRect.Size.AspectRatio == _imageSize.AspectRatio) return false; diff --git a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs index 00cc5864f5..0eb7ae2e31 100644 --- a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs +++ b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs @@ -42,7 +42,7 @@ namespace Avalonia.Utilities { if (!_singleValue.HasValue || !EqualityComparer.Default.Equals(_singleValue.Value.Key, key)) { - value = default(TValue); + value = default; return false; } else diff --git a/src/Avalonia.Base/Utilities/StringTokenizer.cs b/src/Avalonia.Base/Utilities/StringTokenizer.cs index 726c9735ef..aad742e02b 100644 --- a/src/Avalonia.Base/Utilities/StringTokenizer.cs +++ b/src/Avalonia.Base/Utilities/StringTokenizer.cs @@ -63,7 +63,7 @@ namespace Avalonia.Utilities } else { - result = default(Int32); + result = default; return false; } } @@ -87,7 +87,7 @@ namespace Avalonia.Utilities } else { - result = default(double); + result = default; return false; } } diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index 78de00078e..83a0dd3ce1 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -1118,7 +1118,7 @@ namespace Avalonia.Controls EnsureColumnHeadersVisibility(); if (!newValueCols) { - _columnHeadersPresenter.Measure(default(Size)); + _columnHeadersPresenter.Measure(default); } else { @@ -1159,7 +1159,7 @@ namespace Avalonia.Controls _topLeftCornerHeader.IsVisible = newValueRows && newValueCols; if (_topLeftCornerHeader.IsVisible) { - _topLeftCornerHeader.Measure(default(Size)); + _topLeftCornerHeader.Measure(default); } } diff --git a/src/Avalonia.Controls.DataGrid/IndexToValueTable.cs b/src/Avalonia.Controls.DataGrid/IndexToValueTable.cs index 65c3af344c..68a2fc562f 100644 --- a/src/Avalonia.Controls.DataGrid/IndexToValueTable.cs +++ b/src/Avalonia.Controls.DataGrid/IndexToValueTable.cs @@ -422,7 +422,7 @@ namespace Avalonia.Controls else { found = false; - return default(T); + return default; } } diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index 5b2356a7ce..196fd898cf 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -41,7 +41,7 @@ namespace Avalonia.Platform { _draggedData = data; _lastRoot = null; - _lastPosition = default(Point); + _lastPosition = default; _allowedEffects = allowedEffects; using (_inputManager.PreProcess.OfType().Subscribe(ProcessMouseEvents)) diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs index 328facba0b..51f85a3e3d 100644 --- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs @@ -500,7 +500,7 @@ namespace Avalonia.Controls.Presenters if (e.OldValue != null) { - Offset = default(Vector); + Offset = default; } } @@ -542,7 +542,7 @@ namespace Avalonia.Controls.Presenters if (logicalScroll != scrollable.IsLogicalScrollEnabled) { UpdateScrollableSubscription(Child); - Offset = default(Vector); + Offset = default; InvalidateMeasure(); } else if (scrollable.IsLogicalScrollEnabled) diff --git a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs index 6ff72751a6..7b663dd017 100644 --- a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs +++ b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs @@ -49,7 +49,7 @@ namespace Avalonia.Controls.Utils public bool TryGetLastState(out TState? _state) { - _state = default(TState); + _state = default; if (!IsLastState) return false; diff --git a/src/Avalonia.FreeDesktop/DBusMenu.cs b/src/Avalonia.FreeDesktop/DBusMenu.cs index 3a1c65e7c9..7e22988270 100644 --- a/src/Avalonia.FreeDesktop/DBusMenu.cs +++ b/src/Avalonia.FreeDesktop/DBusMenu.cs @@ -36,10 +36,10 @@ namespace Avalonia.FreeDesktop.DBusMenu [Dictionary] class DBusMenuProperties { - public uint Version { get; set; } = default (uint); - public string? TextDirection { get; set; } = default (string); - public string? Status { get; set; } = default (string); - public string[]? IconThemePath { get; set; } = default (string[]); + public uint Version { get; set; } = default; + public string? TextDirection { get; set; } = default; + public string? Status { get; set; } = default; + public string[]? IconThemePath { get; set; } = default; } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs index ac54365f51..6032f3a92c 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs @@ -25,7 +25,7 @@ namespace Avalonia.LinuxFramebuffer Surfaces = new object[] { _outputBackend }; - Invalidate(default(Rect)); + Invalidate(default); _inputBackend.Initialize(this, e => Input?.Invoke(e)); } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 48e8c761eb..8b71f4e17e 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -224,9 +224,9 @@ namespace Avalonia.Skia var impl = (GeometryImpl) geometry; var size = geometry.Bounds.Size; - using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default(PaintWrapper)) + using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default) using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, - size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))) : default(PaintWrapper)) + size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))) : default) { if (fill.Paint != null) { diff --git a/src/Skia/Avalonia.Skia/GeometryImpl.cs b/src/Skia/Avalonia.Skia/GeometryImpl.cs index 1141763097..15a3ebff40 100644 --- a/src/Skia/Avalonia.Skia/GeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/GeometryImpl.cs @@ -245,7 +245,7 @@ namespace Avalonia.Skia { CachedStrokePath?.Dispose(); CachedGeometryRenderBounds = default; - _cachedStrokeWidth = default(float); + _cachedStrokeWidth = default; } } } diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs index a5474803a1..5526ee69ac 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs @@ -156,7 +156,7 @@ namespace Avalonia.Win32.Interop.Wpf _impl.ImageSource = _image; RemoveAndDispose(ref _backBuffer); - if (size == default(IntSize)) + if (size == default) { _image.Lock(); _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero); @@ -171,7 +171,7 @@ namespace Avalonia.Win32.Interop.Wpf static void RemoveAndDispose(ref T d) where T : IDisposable { d?.Dispose(); - d = default(T); + d = default; } void Swap() diff --git a/src/Windows/Avalonia.Win32/DataObject.cs b/src/Windows/Avalonia.Win32/DataObject.cs index b7a567ea97..7d22e57a30 100644 --- a/src/Windows/Avalonia.Win32/DataObject.cs +++ b/src/Windows/Avalonia.Win32/DataObject.cs @@ -205,7 +205,7 @@ namespace Avalonia.Win32 if (string.IsNullOrEmpty(fmt) || !_wrapped.Contains(fmt)) return DV_E_FORMATETC; - * medium = default(Interop.STGMEDIUM); + * medium = default; medium->tymed = TYMED.TYMED_HGLOBAL; return WriteDataToHGlobal(fmt, ref medium->unionmember); } diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index b4eb6d8851..8bbdfe5fd9 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -121,7 +121,7 @@ namespace Avalonia.Win32 _dragDevice, RawDragEventType.DragLeave, _target, - default(Point), + default, null, DragDropEffects.None, RawInputModifiers.None diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs index 2d1dad6be0..469bcecfb9 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs @@ -569,7 +569,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var target = CreateTarget(itemCount: 10); var items = (IList)target.Items; target.ApplyTemplate(); - target.Measure(default(Size)); + target.Measure(default); target.Arrange(default); // Check for issue #591: this should not throw. From 208b0264c64e25282870c036e02c7794daf173ee Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 10:54:22 +1100 Subject: [PATCH 08/30] broken GetRequiredService for _useGL --- src/Browser/Avalonia.Browser/AvaloniaView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Browser/Avalonia.Browser/AvaloniaView.cs b/src/Browser/Avalonia.Browser/AvaloniaView.cs index 153a8c6c1d..294216ee03 100644 --- a/src/Browser/Avalonia.Browser/AvaloniaView.cs +++ b/src/Browser/Avalonia.Browser/AvaloniaView.cs @@ -106,7 +106,7 @@ namespace Avalonia.Browser _dpi = DomHelper.ObserveDpi(OnDpiChanged); - _useGL = AvaloniaLocator.Current.GetRequiredService() != null; + _useGL = AvaloniaLocator.Current.GetService() != null; if (_useGL) { From 9ea174ce0af7f1f9f89c0bc5492d74cb177b1f9d Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 10:58:47 +1100 Subject: [PATCH 09/30] Storage/getItem can be null https://developer.mozilla.org/en-US/docs/Web/API/Storage/getItem --- src/Browser/Avalonia.Browser/Interop/StorageHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs b/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs index c44af810d1..e50f8790ef 100644 --- a/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs +++ b/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs @@ -45,7 +45,7 @@ internal static partial class StorageHelper [JSImport("StorageItem.getItems", AvaloniaModule.StorageModuleName)] [return: JSMarshalAs>] - public static partial Task GetItems(JSObject item); + public static partial Task GetItems(JSObject item); [JSImport("StorageItems.itemsArray", AvaloniaModule.StorageModuleName)] public static partial JSObject[] ItemsArray(JSObject item); From 4b1a5a28b16d19aafa3155d33914a2e4535a3206 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:06:47 +1100 Subject: [PATCH 10/30] OpenFilePickerAsync cant return null --- samples/ControlCatalog/ViewModels/ContextPageViewModel.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/ContextPageViewModel.cs b/samples/ControlCatalog/ViewModels/ContextPageViewModel.cs index 4cfb00625e..4a5462a58b 100644 --- a/samples/ControlCatalog/ViewModels/ContextPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/ContextPageViewModel.cs @@ -56,12 +56,9 @@ namespace ControlCatalog.ViewModels var result = await window.StorageProvider.OpenFilePickerAsync(new Avalonia.Platform.Storage.FilePickerOpenOptions() { AllowMultiple = true }); - if (result != null) + foreach (var file in result) { - foreach (var file in result) - { - System.Diagnostics.Debug.WriteLine($"Opened: {file.Name}"); - } + System.Diagnostics.Debug.WriteLine($"Opened: {file.Name}"); } } From 374c0c4e3bd596d7166e3634c1ae0e146f894210 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:08:04 +1100 Subject: [PATCH 11/30] screens in ScreenPage sampel cant be null --- samples/ControlCatalog/Pages/ScreenPage.cs | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index 6af4cf353e..b5b80fb147 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -36,44 +36,44 @@ namespace ControlCatalog.Pages var drawBrush = Brushes.Black; Pen p = new Pen(drawBrush); - if (screens != null) - foreach (Screen screen in screens) + + foreach (Screen screen in screens) + { + if (screen.Bounds.X / 10f < _leftMost) { - if (screen.Bounds.X / 10f < _leftMost) - { - _leftMost = screen.Bounds.X / 10f; - Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); - return; - } + _leftMost = screen.Bounds.X / 10f; + Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); + return; + } - Rect boundsRect = new Rect(screen.Bounds.X / 10f + Math.Abs(_leftMost), screen.Bounds.Y / 10f, screen.Bounds.Width / 10f, - screen.Bounds.Height / 10f); - Rect workingAreaRect = new Rect(screen.WorkingArea.X / 10f + Math.Abs(_leftMost), screen.WorkingArea.Y / 10f, screen.WorkingArea.Width / 10f, - screen.WorkingArea.Height / 10f); - - context.DrawRectangle(p, boundsRect); - context.DrawRectangle(p, workingAreaRect); + Rect boundsRect = new Rect(screen.Bounds.X / 10f + Math.Abs(_leftMost), screen.Bounds.Y / 10f, screen.Bounds.Width / 10f, + screen.Bounds.Height / 10f); + Rect workingAreaRect = new Rect(screen.WorkingArea.X / 10f + Math.Abs(_leftMost), screen.WorkingArea.Y / 10f, screen.WorkingArea.Width / 10f, + screen.WorkingArea.Height / 10f); + context.DrawRectangle(p, boundsRect); + context.DrawRectangle(p, workingAreaRect); - var formattedText = CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}"); - context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height)); - formattedText = - CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); - context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20)); + var formattedText = CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}"); + context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height)); - formattedText = CreateFormattedText($"Scaling: {screen.Scaling * 100}%"); - context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); + formattedText = + CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); + context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20)); - formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}"); + formattedText = CreateFormattedText($"Scaling: {screen.Scaling * 100}%"); + context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); - context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); + formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}"); - formattedText = - CreateFormattedText( - $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}"); - context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 80)); - } + context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); + + formattedText = + CreateFormattedText( + $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}"); + context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 80)); + } context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10)); } From 1b71714b76938278b744d475eb64b08d9156c187 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:09:22 +1100 Subject: [PATCH 12/30] brush in cataloge sample can be null --- samples/ControlCatalog/Pages/PointerCanvas.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/PointerCanvas.cs b/samples/ControlCatalog/Pages/PointerCanvas.cs index 7d26da8603..da1ff5442d 100644 --- a/samples/ControlCatalog/Pages/PointerCanvas.cs +++ b/samples/ControlCatalog/Pages/PointerCanvas.cs @@ -24,7 +24,7 @@ public class PointerCanvas : Control { struct CanvasPoint { - public IBrush Brush; + public IBrush? Brush; public Point Point; public double Radius; public double? Pressure; From c89f221f6d2f7bc9fef9ea9bca7de7fc41ba8105 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:14:29 +1100 Subject: [PATCH 13/30] remove some duplicate casts --- .../Controls/NameScopeExtensions.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Base/Controls/NameScopeExtensions.cs b/src/Avalonia.Base/Controls/NameScopeExtensions.cs index 3895b6ceb9..7d80d2fde7 100644 --- a/src/Avalonia.Base/Controls/NameScopeExtensions.cs +++ b/src/Avalonia.Base/Controls/NameScopeExtensions.cs @@ -25,13 +25,18 @@ namespace Avalonia.Controls var result = nameScope.Find(name); - if (result != null && !(result is T)) + if (result == null) { - throw new InvalidOperationException( - $"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'."); + return (T?)result; + } + + if (result is T typed) + { + return typed; } - return (T?)result; + throw new InvalidOperationException( + $"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'."); } /// @@ -74,13 +79,13 @@ namespace Avalonia.Controls throw new KeyNotFoundException($"Could not find control '{name}'."); } - if (!(result is T)) + if (result is T typed) { - throw new InvalidOperationException( - $"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'."); + return typed; } - return (T)result; + throw new InvalidOperationException( + $"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'."); } /// From 4ab3eb106423fe0e2baaa43311e5bb1e561db98b Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:18:40 +1100 Subject: [PATCH 14/30] . --- src/Avalonia.Build.Tasks/ComInteropHelper.cs | 4 +--- .../ScrollViewerIRefreshInfoProviderAdapter.cs | 4 ++-- .../Templates/FuncTreeDataTemplate`1.cs | 4 ++-- .../ViewModels/ControlDetailsViewModel.cs | 8 ++++---- .../Markup/Parsers/SelectorGrammar.cs | 12 +++++++----- src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs | 2 +- .../Avalonia.Win32/WindowImpl.CustomCaptionProc.cs | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Avalonia.Build.Tasks/ComInteropHelper.cs b/src/Avalonia.Build.Tasks/ComInteropHelper.cs index 007231417d..c990741e1e 100644 --- a/src/Avalonia.Build.Tasks/ComInteropHelper.cs +++ b/src/Avalonia.Build.Tasks/ComInteropHelper.cs @@ -65,10 +65,8 @@ namespace Avalonia.Build.Tasks { 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") { var callSite = new CallSite(methodDescription.ReturnType) { CallingConvention = MethodCallingConvention.StdCall }; diff --git a/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs b/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs index c3aebc82c5..844973bd28 100644 --- a/src/Avalonia.Controls/PullToRefresh/ScrollViewerIRefreshInfoProviderAdapter.cs +++ b/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"); } - 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"); } - MakeInteractionSource(content.Parent as InputElement); + MakeInteractionSource(parent); if (_scrollViewer != null) { diff --git a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs index d4ecdd6cf0..a093d976f7 100644 --- a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs +++ b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs @@ -59,7 +59,7 @@ namespace Avalonia.Controls.Templates /// The untyped function. private static Func CastMatch(Func f) { - return o => (o is T) && f((T)o); + return o => o is T arg && f(arg); } /// @@ -72,7 +72,7 @@ namespace Avalonia.Controls.Templates { return (o, s) => f((T)o!, s); } - + /// /// Casts a function with a typed parameter to an untyped function. /// diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs index 5cf9e17ecf..8bff9ccde0 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs @@ -33,12 +33,12 @@ namespace Avalonia.Diagnostics.ViewModels { _avaloniaObject = avaloniaObject; - TreePage = treePage; - Layout = avaloniaObject is Visual - ? new ControlLayoutViewModel((Visual)avaloniaObject) + TreePage = treePage; + Layout = avaloniaObject is Visual visual + ? new ControlLayoutViewModel(visual) : default; - NavigateToProperty(_avaloniaObject, (_avaloniaObject as Control)?.Name ?? _avaloniaObject.ToString()); + NavigateToProperty(_avaloniaObject, (_avaloniaObject as Control)?.Name ?? _avaloniaObject.ToString()); AppliedStyles = new ObservableCollection(); PseudoClasses = new ObservableCollection(); diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs index 4d6d16a3ce..dbf37f0900 100644 --- a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs +++ b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs @@ -552,7 +552,8 @@ namespace Avalonia.Markup.Parsers 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) { - 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) { - return obj is PropertySyntax && - ((PropertySyntax)obj).Property == Property && - ((PropertySyntax)obj).Value == Value; + return obj is PropertySyntax syntax && + syntax.Property == Property && + syntax.Value == Value; } } diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs index b8648dfc50..3bfbf4bd92 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs @@ -28,7 +28,7 @@ namespace Avalonia.Win32.Interop.Wpf public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; - return obj is IntSize && Equals((IntSize) obj); + return obj is IntSize size && Equals(size); } public override int GetHashCode() diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index d393bd304a..fb27ab7856 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -109,7 +109,7 @@ namespace Avalonia.Win32 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)) { From 0520d25ed580b86b3e3d1d7d4c4d614ce009d887 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:23:21 +1100 Subject: [PATCH 15/30] missing OnItemTemplatePropertyChanged call in AutoCompleteBox --- src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs index e0d986f2b4..f9978d2795 100644 --- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs @@ -474,6 +474,7 @@ namespace Avalonia.Controls FilterModeProperty.Changed.AddClassHandler((x,e) => x.OnFilterModePropertyChanged(e)); ItemFilterProperty.Changed.AddClassHandler((x,e) => x.OnItemFilterPropertyChanged(e)); ItemsProperty.Changed.AddClassHandler((x,e) => x.OnItemsPropertyChanged(e)); + ItemTemplateProperty.Changed.AddClassHandler((x,e) => x.OnItemTemplatePropertyChanged(e)); IsEnabledProperty.Changed.AddClassHandler((x,e) => x.OnControlIsEnabledChanged(e)); } From 81c06203676899fd45135e9390aeb002f155de61 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:24:35 +1100 Subject: [PATCH 16/30] Update src/Avalonia.Controls/Platform/PlatformManager.cs Co-authored-by: Max Katz --- src/Avalonia.Controls/Platform/PlatformManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Platform/PlatformManager.cs b/src/Avalonia.Controls/Platform/PlatformManager.cs index b01fc28831..79ace0b329 100644 --- a/src/Avalonia.Controls/Platform/PlatformManager.cs +++ b/src/Avalonia.Controls/Platform/PlatformManager.cs @@ -21,7 +21,7 @@ namespace Avalonia.Controls.Platform } public static ITrayIconImpl? CreateTrayIcon() => - s_designerMode ? null : AvaloniaLocator.Current.GetRequiredService().CreateTrayIcon(); + s_designerMode ? null : AvaloniaLocator.Current.GetService()?.CreateTrayIcon(); public static IWindowImpl CreateWindow() From cc6f0d1af15cf4a37e16f0ea9469c4171d740f8f Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:28:59 +1100 Subject: [PATCH 17/30] should GetLayoutVisibleWindowDiscardAnchor be used? --- .../Repeater/ViewportManager.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Avalonia.Controls/Repeater/ViewportManager.cs b/src/Avalonia.Controls/Repeater/ViewportManager.cs index 10e3dd57a0..28d6911350 100644 --- a/src/Avalonia.Controls/Repeater/ViewportManager.cs +++ b/src/Avalonia.Controls/Repeater/ViewportManager.cs @@ -124,22 +124,6 @@ namespace Avalonia.Controls } } } - - private Rect GetLayoutVisibleWindowDiscardAnchor() - { - var visibleWindow = _visibleWindow; - - if (HasScroller) - { - visibleWindow = new Rect( - visibleWindow.X + _layoutExtent.X + _expectedViewportShift.X + _unshiftableShift.X, - visibleWindow.Y + _layoutExtent.Y + _expectedViewportShift.Y + _unshiftableShift.Y, - visibleWindow.Width, - visibleWindow.Height); - } - - return visibleWindow; - } public Rect GetLayoutVisibleWindow() { From ebb7a95c0e6046bea6fc6a13ede18991e94abc56 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 11:32:04 +1100 Subject: [PATCH 18/30] missing ScrollGestureEndedEvent mapping --- src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs index 328facba0b..61ad5e802b 100644 --- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs @@ -94,6 +94,7 @@ namespace Avalonia.Controls.Presenters { AddHandler(RequestBringIntoViewEvent, BringIntoViewRequested); AddHandler(Gestures.ScrollGestureEvent, OnScrollGesture); + AddHandler(Gestures.ScrollGestureEndedEvent, OnScrollGestureEnded); this.GetObservable(ChildProperty).Subscribe(UpdateScrollableSubscription); } From a642cba9d24a91dc1006d91fc7fb28f7a7870233 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 14:51:01 +1100 Subject: [PATCH 19/30] Update NameScopeExtensions.cs --- src/Avalonia.Base/Controls/NameScopeExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Controls/NameScopeExtensions.cs b/src/Avalonia.Base/Controls/NameScopeExtensions.cs index 7d80d2fde7..0abd5e56f7 100644 --- a/src/Avalonia.Base/Controls/NameScopeExtensions.cs +++ b/src/Avalonia.Base/Controls/NameScopeExtensions.cs @@ -27,7 +27,7 @@ namespace Avalonia.Controls if (result == null) { - return (T?)result; + return null; } if (result is T typed) From 7db93a75e42535c8125437d71a199e6547a2cdbe Mon Sep 17 00:00:00 2001 From: daniel Date: Fri, 6 Jan 2023 08:54:04 +0200 Subject: [PATCH 20/30] Move missing calling InvalidateMirrorTransform --- src/Avalonia.Base/Visual.cs | 1 + src/Avalonia.Controls/Control.cs | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs index 5930df5483..7e22303964 100644 --- a/src/Avalonia.Base/Visual.cs +++ b/src/Avalonia.Base/Visual.cs @@ -480,6 +480,7 @@ namespace Avalonia { AttachToCompositor(compositingRenderer.Compositor); } + InvalidateMirrorTransform(); OnAttachedToVisualTree(e); AttachedToVisualTree?.Invoke(this, e); InvalidateVisual(); diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index 26db431a0e..ed24c3c7c2 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -392,14 +392,6 @@ namespace Avalonia.Controls OnUnloadedCore(); } - /// - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - - InvalidateMirrorTransform(); - } - /// protected override void OnGotFocus(GotFocusEventArgs e) { From 1396c5aac7ba0987e06d828589b1c53b52726a62 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 19:48:05 +1100 Subject: [PATCH 21/30] Update WriteableBitmapImpl.cs --- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index 12d9471204..9864a14a9c 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -97,7 +97,7 @@ namespace Avalonia.Skia SKColorType colorType = format.ToSkColorType(); SKAlphaType alphaType = alphaFormat.ToSkAlphaType(); - var runtimePlatform = AvaloniaLocator.Current.GetRequiredService(); + var runtimePlatform = AvaloniaLocator.Current.GetService(); if (runtimePlatform != null) { From 5fdb513303b7b6cccca5b5e7416e34c3e061afa5 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Fri, 6 Jan 2023 12:18:15 +0300 Subject: [PATCH 22/30] [Text] [Debug] fix Text output of TextRunDebuggerProxy --- src/Avalonia.Base/Media/TextFormatting/TextRun.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/TextRun.cs b/src/Avalonia.Base/Media/TextFormatting/TextRun.cs index 0306054767..e79c2ed8b3 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextRun.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextRun.cs @@ -44,7 +44,7 @@ namespace Avalonia.Media.TextFormatting fixed (char* charsPtr = characterBuffer.Span) { - return new string(charsPtr, 0, characterBuffer.Span.Length); + return new string(charsPtr, _textRun.CharacterBufferReference.OffsetToFirstChar, _textRun.Length); } } } From ac01ee00e68e0bdfbe6f0992a4743bf4472561ae Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Fri, 6 Jan 2023 20:38:05 +1100 Subject: [PATCH 23/30] . --- samples/Directory.Build.props | 5 ++--- tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 471c42ec07..3b14f0ce12 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -2,9 +2,8 @@ false $(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\netcoreapp2.0\Avalonia.Designer.HostApp.dll + false + 11 - - false - diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj index b9c2a619d9..17448ade76 100644 --- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj +++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj @@ -4,7 +4,6 @@ false Library false - latest ..\..\build\avalonia.snk false true From d1037a73699bfff23cd25a9c9d08bf66e3948e70 Mon Sep 17 00:00:00 2001 From: AlmightyJu Date: Fri, 6 Jan 2023 14:26:00 +0000 Subject: [PATCH 24/30] Fix DataGridTemplateColumn reusing edit control when exiting edit mode --- src/Avalonia.Controls.DataGrid/DataGrid.cs | 1 + src/Avalonia.Controls.DataGrid/DataGridColumn.cs | 11 +++++++++++ .../DataGridTemplateColumn.cs | 16 ++++++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index 78de00078e..cadecc03bc 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -4152,6 +4152,7 @@ namespace Avalonia.Controls if (exitEditingMode) { + CurrentColumn.EndCellEditInternal(); _editingColumnIndex = -1; editingCell.UpdatePseudoClasses(); diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs index d9d80acdc3..63e7e1e2b3 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs @@ -800,11 +800,22 @@ namespace Avalonia.Controls protected internal virtual void RefreshCellContent(Control element, string propertyName) { } + /// + /// When overridden in a derived class, called when a cell in the column exits editing mode. + /// + protected virtual void EndCellEdit() + { } + internal void CancelCellEditInternal(Control editingElement, object uneditedValue) { CancelCellEdit(editingElement, uneditedValue); } + internal void EndCellEditInternal() + { + EndCellEdit(); + } + /// /// Coerces a DataGridLength to a valid value. If any value components are double.NaN, this method /// coerces them to a proper initial value. For star columns, the desired width is calculated based diff --git a/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs index 24ae358dcc..516e9cf6c2 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs @@ -55,17 +55,25 @@ namespace Avalonia.Controls get => _cellEditingCellTemplate; set => SetAndRaise(CellEditingTemplateProperty, ref _cellEditingCellTemplate, value); } - - private static void OnCellTemplateChanged(AvaloniaPropertyChangedEventArgs e) + + private bool _forceGenerateCellFromTemplate; + + protected override void EndCellEdit() { - var oldValue = (IDataTemplate)e.OldValue; - var value = (IDataTemplate)e.NewValue; + //the next call to generate element should not resuse the current content as we need to exit edit mode + _forceGenerateCellFromTemplate = true; + base.EndCellEdit(); } protected override Control GenerateElement(DataGridCell cell, object dataItem) { if (CellTemplate != null) { + if (_forceGenerateCellFromTemplate) + { + _forceGenerateCellFromTemplate = false; + return CellTemplate.Build(dataItem); + } return (CellTemplate is IRecyclingDataTemplate recyclingDataTemplate) ? recyclingDataTemplate.Build(dataItem, cell.Content as Control) : CellTemplate.Build(dataItem); From 84206e93dd9980e9b590398e50e1ba780cb5ce7c Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 03:45:50 +0300 Subject: [PATCH 25/30] [Text] Optimize grapheme and add performance benchmark --- .../TextFormatting/FormattedTextSource.cs | 2 +- .../Media/TextFormatting/TextCharacters.cs | 4 +- .../Media/TextFormatting/Unicode/Grapheme.cs | 14 +++-- .../Unicode/GraphemeEnumerator.cs | 4 +- src/Avalonia.Controls/TextBox.cs | 2 +- .../GraphemeBreakClassTrieGeneratorTests.cs | 4 +- .../Text/HugeTextLayout.cs | 62 +++++++++++++++++++ .../Media/TextFormatting/TextLayoutTests.cs | 8 +-- 8 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs diff --git a/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs b/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs index 4472ba87eb..49d94b511d 100644 --- a/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs +++ b/src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs @@ -132,7 +132,7 @@ namespace Avalonia.Media.TextFormatting { var grapheme = graphemeEnumerator.Current; - finalLength += grapheme.Text.Length; + finalLength += grapheme.Length; if (finalLength >= length) { diff --git a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs index db035b8750..1a48151834 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs @@ -196,7 +196,7 @@ namespace Avalonia.Media.TextFormatting break; } - count += grapheme.Text.Length; + count += grapheme.Length; } return new UnshapedTextRun(characterBufferRange.CharacterBufferReference, count, defaultProperties, biDiLevel); @@ -264,7 +264,7 @@ namespace Avalonia.Media.TextFormatting } } - length += currentGrapheme.Text.Length; + length += currentGrapheme.Length; } return length > 0; diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/Grapheme.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/Grapheme.cs index 69015fb17d..f75168083c 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/Grapheme.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/Grapheme.cs @@ -7,10 +7,11 @@ namespace Avalonia.Media.TextFormatting.Unicode /// public readonly ref struct Grapheme { - public Grapheme(Codepoint firstCodepoint, ReadOnlySpan text) + public Grapheme(Codepoint firstCodepoint, int offset, int length) { FirstCodepoint = firstCodepoint; - Text = text; + Offset = offset; + Length = length; } /// @@ -19,8 +20,13 @@ namespace Avalonia.Media.TextFormatting.Unicode public Codepoint FirstCodepoint { get; } /// - /// The text that is representing the . + /// The Offset to the FirstCodepoint /// - public ReadOnlySpan Text { get; } + public int Offset { get; } + + /// + /// The length of the grapheme cluster + /// + public int Length { get; } } } diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs index 5ca120c856..dc21e06813 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs @@ -185,9 +185,7 @@ namespace Avalonia.Media.TextFormatting.Unicode Return: - var text = _text.Take(processor.CurrentCodeUnitOffset); - - Current = new Grapheme(firstCodepoint, text.Span); + Current = new Grapheme(firstCodepoint, _text.OffsetToFirstChar, processor.CurrentCodeUnitOffset); _text = _text.Skip(processor.CurrentCodeUnitOffset); diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 9a2ee12dc3..0e1024c027 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -981,7 +981,7 @@ namespace Avalonia.Controls } } - length += grapheme.Text.Length; + length += grapheme.Length; } if (length < input.Length) diff --git a/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGeneratorTests.cs b/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGeneratorTests.cs index 4e0207a85d..c57bd6c002 100644 --- a/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGeneratorTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGeneratorTests.cs @@ -42,7 +42,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting enumerator.MoveNext(); - var actual = enumerator.Current.Text; + var actual = text.AsSpan(enumerator.Current.Offset, enumerator.Current.Length); var pass = true; @@ -93,7 +93,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting while (enumerator.MoveNext()) { - Assert.Equal(1, enumerator.Current.Text.Length); + Assert.Equal(1, enumerator.Current.Length); count++; } diff --git a/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs b/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs new file mode 100644 index 0000000000..e1b3c6a99c --- /dev/null +++ b/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs @@ -0,0 +1,62 @@ +using System; +using Avalonia.Media; +using Avalonia.Media.TextFormatting; +using Avalonia.UnitTests; +using BenchmarkDotNet.Attributes; + +namespace Avalonia.Benchmarks.Text; + +[MemoryDiagnoser] +public class HugeTextLayout : IDisposable +{ + private readonly IDisposable _app; + + public HugeTextLayout() + { + _app = UnitTestApplication.Start( + TestServices.StyledWindow.With( + renderInterface: new NullRenderingPlatform(), + threadingInterface: new NullThreadingPlatform(), + standardCursorFactory: new NullCursorFactory())); + } + + private const string Text = @"Though, the objectives of the development of the prominent landmarks can be neglected in most cases, it should be realized that after the completion of the strategic decision gives rise to The Expertise of Regular Program (Carlton Cartwright in The Book of the Key Factor) +A number of key issues arise from the belief that the explicit examination of strategic management should correlate with the conceptual design. +By all means, the unification of the reliably developed techniques indicates the importance of the ultimate advantage of episodic skill over alternate practices. +Let's consider, that the portion of the continuing support can be regarded as relentlessly insignificant. The hardware maintenance focuses our attention on the structure absorption. The real reason of the permanent growth drastically the preliminary action plan the ultimate advantage of useful probability over alternate practices. +Let it not be said that a section of the essential component discards the principle of the more interconnection of critical thinking with productivity boosting of the referential arguments. +One should, however, not forget that concentration of violations of the strategic management requires urgent actions to be taken towards the comprehensive set of policy statements. Therefore, the concept of the design aspects can be treated as the only solution. +In a loose sense concentration of the center of the critical thinking provides a deep insight into the emergency planning. The comparison is quite a powerful matter. +Resulting from review or analysis of threats and opportunities, we can presume that either significant improvement or basics of planning and scheduling reveals the patterns of the final draft. Therefore, the concept of the crucial component can be treated as the only solution. +One should, nevertheless, consider that the exceptional results of the diverse sources of information gives an overview of the production cycle. It should rather be regarded as an integral part of the direct access to key resources. +Admitting that the possibility of achieving the results of the constructive criticism, as far as the strategic management is questionable, cannot rely only on the critical thinking. It may reveal how the systems approach partially the comprehensive project management. We must be ready for outline design stage and network development investigation of every contradiction between the effective time management and the efficient decision the network development. Everyone understands what it takes to the draft analysis and prior decisions and early design solutions. In any case, we can systematically change the mechanism of the sources and influences of the continuing financing doctrine. This could exceedingly be a result of a task analysis the hardware maintenance. The real reason of the strategic planning seemingly the influence on eventual productivity. Everyone understands what it takes to the well-known practice. Therefore, the concept of the productivity boost can be treated as the only solution the driving factor. It may reveal how the matters of peculiar interest slowly the goals and objectives or the diverse sources of information the positive influence of any major outcomes complete failure of the supposed theory. +In respect that the structure of the sufficient amount poses problems and challenges for both the set of related commands and controls and the ability bias."; + + [Benchmark] + public TextLayout BuildTextLayout() => new TextLayout(Text, Typeface.Default, 12d, Brushes.Black); + + private const string Emojis = @"๐Ÿ˜€ ๐Ÿ˜ ๐Ÿ˜‚ ๐Ÿคฃ ๐Ÿ˜ƒ ๐Ÿ˜„ ๐Ÿ˜… ๐Ÿ˜† ๐Ÿ˜‰ ๐Ÿ˜Š ๐Ÿ˜‹ ๐Ÿ˜Ž ๐Ÿ˜ ๐Ÿ˜˜ ๐Ÿฅฐ ๐Ÿ˜— ๐Ÿ˜™ ๐Ÿ˜š โ˜บ๏ธ ๐Ÿ™‚ ๐Ÿค— ๐Ÿคฉ ๐Ÿค” ๐Ÿคจ ๐Ÿ˜ ๐Ÿ˜‘ ๐Ÿ˜ถ ๐Ÿ™„ ๐Ÿ˜ ๐Ÿ˜ฃ ๐Ÿ˜ฅ ๐Ÿ˜ฎ ๐Ÿค ๐Ÿ˜ฏ ๐Ÿ˜ช ๐Ÿ˜ซ ๐Ÿ˜ด ๐Ÿ˜Œ ๐Ÿ˜› ๐Ÿ˜œ ๐Ÿ˜ ๐Ÿคค ๐Ÿ˜’ ๐Ÿ˜“ ๐Ÿ˜” ๐Ÿ˜• ๐Ÿ™ƒ ๐Ÿค‘ ๐Ÿ˜ฒ โ˜น๏ธ ๐Ÿ™ ๐Ÿ˜– ๐Ÿ˜ž ๐Ÿ˜Ÿ ๐Ÿ˜ค ๐Ÿ˜ข ๐Ÿ˜ญ ๐Ÿ˜ฆ ๐Ÿ˜ง ๐Ÿ˜จ ๐Ÿ˜ฉ ๐Ÿคฏ ๐Ÿ˜ฌ ๐Ÿ˜ฐ ๐Ÿ˜ฑ ๐Ÿฅต ๐Ÿฅถ ๐Ÿ˜ณ ๐Ÿคช ๐Ÿ˜ต ๐Ÿ˜ก ๐Ÿ˜  ๐Ÿคฌ ๐Ÿ˜ท ๐Ÿค’ ๐Ÿค• ๐Ÿคข ๐Ÿคฎ ๐Ÿคง ๐Ÿ˜‡ ๐Ÿค  ๐Ÿคก ๐Ÿฅณ ๐Ÿฅด ๐Ÿฅบ ๐Ÿคฅ ๐Ÿคซ ๐Ÿคญ ๐Ÿง ๐Ÿค“ ๐Ÿ˜ˆ ๐Ÿ‘ฟ ๐Ÿ‘น ๐Ÿ‘บ ๐Ÿ’€ ๐Ÿ‘ป ๐Ÿ‘ฝ ๐Ÿค– ๐Ÿ’ฉ ๐Ÿ˜บ ๐Ÿ˜ธ ๐Ÿ˜น ๐Ÿ˜ป ๐Ÿ˜ผ ๐Ÿ˜ฝ ๐Ÿ™€ ๐Ÿ˜ฟ ๐Ÿ˜พ +๐Ÿ‘ถ ๐Ÿ‘ง ๐Ÿง’ ๐Ÿ‘ฆ ๐Ÿ‘ฉ ๐Ÿง‘ ๐Ÿ‘จ ๐Ÿ‘ต ๐Ÿง“ ๐Ÿ‘ด ๐Ÿ‘ฒ ๐Ÿ‘ณโ€โ™€๏ธ ๐Ÿ‘ณโ€โ™‚๏ธ ๐Ÿง• ๐Ÿง” ๐Ÿ‘ฑโ€โ™‚๏ธ ๐Ÿ‘ฑโ€โ™€๏ธ ๐Ÿ‘จโ€๐Ÿฆฐ ๐Ÿ‘ฉโ€๐Ÿฆฐ ๐Ÿ‘จโ€๐Ÿฆฑ ๐Ÿ‘ฉโ€๐Ÿฆฑ ๐Ÿ‘จโ€๐Ÿฆฒ ๐Ÿ‘ฉโ€๐Ÿฆฒ ๐Ÿ‘จโ€๐Ÿฆณ ๐Ÿ‘ฉโ€๐Ÿฆณ ๐Ÿฆธโ€โ™€๏ธ ๐Ÿฆธโ€โ™‚๏ธ ๐Ÿฆนโ€โ™€๏ธ ๐Ÿฆนโ€โ™‚๏ธ ๐Ÿ‘ฎโ€โ™€๏ธ ๐Ÿ‘ฎโ€โ™‚๏ธ ๐Ÿ‘ทโ€โ™€๏ธ ๐Ÿ‘ทโ€โ™‚๏ธ ๐Ÿ’‚โ€โ™€๏ธ ๐Ÿ’‚โ€โ™‚๏ธ ๐Ÿ•ต๏ธโ€โ™€๏ธ ๐Ÿ•ต๏ธโ€โ™‚๏ธ ๐Ÿ‘ฉโ€โš•๏ธ ๐Ÿ‘จโ€โš•๏ธ ๐Ÿ‘ฉโ€๐ŸŒพ ๐Ÿ‘จโ€๐ŸŒพ ๐Ÿ‘ฉโ€๐Ÿณ ๐Ÿ‘จโ€๐Ÿณ ๐Ÿ‘ฉโ€๐ŸŽ“ ๐Ÿ‘จโ€๐ŸŽ“ ๐Ÿ‘ฉโ€๐ŸŽค ๐Ÿ‘จโ€๐ŸŽค ๐Ÿ‘ฉโ€๐Ÿซ ๐Ÿ‘จโ€๐Ÿซ ๐Ÿ‘ฉโ€๐Ÿญ ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ‘ฉโ€๐Ÿ’ป ๐Ÿ‘จโ€๐Ÿ’ป ๐Ÿ‘ฉโ€๐Ÿ’ผ ๐Ÿ‘จโ€๐Ÿ’ผ ๐Ÿ‘ฉโ€๐Ÿ”ง ๐Ÿ‘จโ€๐Ÿ”ง ๐Ÿ‘ฉโ€๐Ÿ”ฌ ๐Ÿ‘จโ€๐Ÿ”ฌ ๐Ÿ‘ฉโ€๐ŸŽจ ๐Ÿ‘จโ€๐ŸŽจ ๐Ÿ‘ฉโ€๐Ÿš’ ๐Ÿ‘จโ€๐Ÿš’ ๐Ÿ‘ฉโ€โœˆ๏ธ ๐Ÿ‘จโ€โœˆ๏ธ ๐Ÿ‘ฉโ€๐Ÿš€ ๐Ÿ‘จโ€๐Ÿš€ ๐Ÿ‘ฉโ€โš–๏ธ ๐Ÿ‘จโ€โš–๏ธ ๐Ÿ‘ฐ ๐Ÿคต ๐Ÿ‘ธ ๐Ÿคด ๐Ÿคถ ๐ŸŽ… ๐Ÿง™โ€โ™€๏ธ ๐Ÿง™โ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐Ÿงโ€โ™‚๏ธ ๐Ÿง›โ€โ™€๏ธ ๐Ÿง›โ€โ™‚๏ธ ๐ŸงŸโ€โ™€๏ธ ๐ŸงŸโ€โ™‚๏ธ ๐Ÿงžโ€โ™€๏ธ ๐Ÿงžโ€โ™‚๏ธ ๐Ÿงœโ€โ™€๏ธ ๐Ÿงœโ€โ™‚๏ธ ๐Ÿงšโ€โ™€๏ธ ๐Ÿงšโ€โ™‚๏ธ ๐Ÿ‘ผ ๐Ÿคฐ ๐Ÿคฑ ๐Ÿ™‡โ€โ™€๏ธ ๐Ÿ™‡โ€โ™‚๏ธ ๐Ÿ’โ€โ™€๏ธ ๐Ÿ’โ€โ™‚๏ธ ๐Ÿ™…โ€โ™€๏ธ ๐Ÿ™…โ€โ™‚๏ธ ๐Ÿ™†โ€โ™€๏ธ ๐Ÿ™†โ€โ™‚๏ธ ๐Ÿ™‹โ€โ™€๏ธ ๐Ÿ™‹โ€โ™‚๏ธ ๐Ÿคฆโ€โ™€๏ธ ๐Ÿคฆโ€โ™‚๏ธ ๐Ÿคทโ€โ™€๏ธ ๐Ÿคทโ€โ™‚๏ธ ๐Ÿ™Žโ€โ™€๏ธ ๐Ÿ™Žโ€โ™‚๏ธ ๐Ÿ™โ€โ™€๏ธ ๐Ÿ™โ€โ™‚๏ธ ๐Ÿ’‡โ€โ™€๏ธ ๐Ÿ’‡โ€โ™‚๏ธ ๐Ÿ’†โ€โ™€๏ธ ๐Ÿ’†โ€โ™‚๏ธ ๐Ÿง–โ€โ™€๏ธ ๐Ÿง–โ€โ™‚๏ธ ๐Ÿ’… ๐Ÿคณ ๐Ÿ’ƒ ๐Ÿ•บ ๐Ÿ‘ฏโ€โ™€๏ธ ๐Ÿ‘ฏโ€โ™‚๏ธ ๐Ÿ•ด ๐Ÿšถโ€โ™€๏ธ ๐Ÿšถโ€โ™‚๏ธ ๐Ÿƒโ€โ™€๏ธ ๐Ÿƒโ€โ™‚๏ธ ๐Ÿ‘ซ ๐Ÿ‘ญ ๐Ÿ‘ฌ ๐Ÿ’‘ ๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ ๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ ๐Ÿ’ ๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ ๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ ๐Ÿ‘ช ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง ๐Ÿ‘ฉโ€๐Ÿ‘ฆ ๐Ÿ‘ฉโ€๐Ÿ‘ง ๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ ๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง ๐Ÿ‘จโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘ง ๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ ๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง ๐Ÿคฒ ๐Ÿ‘ ๐Ÿ™Œ ๐Ÿ‘ ๐Ÿค ๐Ÿ‘ ๐Ÿ‘Ž ๐Ÿ‘Š โœŠ ๐Ÿค› ๐Ÿคœ ๐Ÿคž โœŒ๏ธ ๐ŸคŸ ๐Ÿค˜ ๐Ÿ‘Œ ๐Ÿ‘ˆ ๐Ÿ‘‰ ๐Ÿ‘† ๐Ÿ‘‡ โ˜๏ธ โœ‹ ๐Ÿคš ๐Ÿ– ๐Ÿ–– ๐Ÿ‘‹ ๐Ÿค™ ๐Ÿ’ช ๐Ÿฆต ๐Ÿฆถ ๐Ÿ–• โœ๏ธ ๐Ÿ™ ๐Ÿ’ ๐Ÿ’„ ๐Ÿ’‹ ๐Ÿ‘„ ๐Ÿ‘… ๐Ÿ‘‚ ๐Ÿ‘ƒ ๐Ÿ‘ฃ ๐Ÿ‘ ๐Ÿ‘€ ๐Ÿง  ๐Ÿฆด ๐Ÿฆท ๐Ÿ—ฃ ๐Ÿ‘ค ๐Ÿ‘ฅ +๐Ÿงฅ ๐Ÿ‘š ๐Ÿ‘• ๐Ÿ‘– ๐Ÿ‘” ๐Ÿ‘— ๐Ÿ‘™ ๐Ÿ‘˜ ๐Ÿ‘  ๐Ÿ‘ก ๐Ÿ‘ข ๐Ÿ‘ž ๐Ÿ‘Ÿ ๐Ÿฅพ ๐Ÿฅฟ ๐Ÿงฆ ๐Ÿงค ๐Ÿงฃ ๐ŸŽฉ ๐Ÿงข ๐Ÿ‘’ ๐ŸŽ“ โ›‘ ๐Ÿ‘‘ ๐Ÿ‘ ๐Ÿ‘› ๐Ÿ‘œ ๐Ÿ’ผ ๐ŸŽ’ ๐Ÿ‘“ ๐Ÿ•ถ ๐Ÿฅฝ ๐Ÿฅผ ๐ŸŒ‚ ๐Ÿงต ๐Ÿงถ +๐Ÿ‘ถ๐Ÿป ๐Ÿ‘ฆ๐Ÿป ๐Ÿ‘ง๐Ÿป ๐Ÿ‘จ๐Ÿป ๐Ÿ‘ฉ๐Ÿป ๐Ÿ‘ฑ๐Ÿปโ€โ™€๏ธ ๐Ÿ‘ฑ๐Ÿป ๐Ÿ‘ด๐Ÿป ๐Ÿ‘ต๐Ÿป ๐Ÿ‘ฒ๐Ÿป ๐Ÿ‘ณ๐Ÿปโ€โ™€๏ธ ๐Ÿ‘ณ๐Ÿป ๐Ÿ‘ฎ๐Ÿปโ€โ™€๏ธ ๐Ÿ‘ฎ๐Ÿป ๐Ÿ‘ท๐Ÿปโ€โ™€๏ธ ๐Ÿ‘ท๐Ÿป ๐Ÿ’‚๐Ÿปโ€โ™€๏ธ ๐Ÿ’‚๐Ÿป ๐Ÿ•ต๐Ÿปโ€โ™€๏ธ ๐Ÿ•ต๐Ÿป ๐Ÿ‘ฉ๐Ÿปโ€โš•๏ธ ๐Ÿ‘จ๐Ÿปโ€โš•๏ธ ๐Ÿ‘ฉ๐Ÿปโ€๐ŸŒพ ๐Ÿ‘จ๐Ÿปโ€๐ŸŒพ ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿณ ๐Ÿ‘จ๐Ÿปโ€๐Ÿณ ๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽ“ ๐Ÿ‘จ๐Ÿปโ€๐ŸŽ“ ๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽค ๐Ÿ‘จ๐Ÿปโ€๐ŸŽค ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿซ ๐Ÿ‘จ๐Ÿปโ€๐Ÿซ ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿญ ๐Ÿ‘จ๐Ÿปโ€๐Ÿญ ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ผ ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ผ ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ง ๐Ÿ‘จ๐Ÿปโ€๐Ÿ”ง ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ฌ ๐Ÿ‘จ๐Ÿปโ€๐Ÿ”ฌ ๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽจ ๐Ÿ‘จ๐Ÿปโ€๐ŸŽจ ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿš’ ๐Ÿ‘จ๐Ÿปโ€๐Ÿš’ ๐Ÿ‘ฉ๐Ÿปโ€โœˆ๏ธ ๐Ÿ‘จ๐Ÿปโ€โœˆ๏ธ ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿš€ ๐Ÿ‘จ๐Ÿปโ€๐Ÿš€ ๐Ÿ‘ฉ๐Ÿปโ€โš–๏ธ ๐Ÿ‘จ๐Ÿปโ€โš–๏ธ ๐Ÿคถ๐Ÿป ๐ŸŽ…๐Ÿป ๐Ÿ‘ธ๐Ÿป ๐Ÿคด๐Ÿป ๐Ÿ‘ฐ๐Ÿป ๐Ÿคต๐Ÿป ๐Ÿ‘ผ๐Ÿป ๐Ÿคฐ๐Ÿป ๐Ÿ™‡๐Ÿปโ€โ™€๏ธ ๐Ÿ™‡๐Ÿป ๐Ÿ’๐Ÿป ๐Ÿ’๐Ÿปโ€โ™‚๏ธ ๐Ÿ™…๐Ÿป ๐Ÿ™…๐Ÿปโ€โ™‚๏ธ ๐Ÿ™†๐Ÿป ๐Ÿ™†๐Ÿปโ€โ™‚๏ธ ๐Ÿ™‹๐Ÿป ๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ ๐Ÿคฆ๐Ÿปโ€โ™€๏ธ ๐Ÿคฆ๐Ÿปโ€โ™‚๏ธ ๐Ÿคท๐Ÿปโ€โ™€๏ธ ๐Ÿคท๐Ÿปโ€โ™‚๏ธ ๐Ÿ™Ž๐Ÿป ๐Ÿ™Ž๐Ÿปโ€โ™‚๏ธ ๐Ÿ™๐Ÿป ๐Ÿ™๐Ÿปโ€โ™‚๏ธ ๐Ÿ’‡๐Ÿป ๐Ÿ’‡๐Ÿปโ€โ™‚๏ธ ๐Ÿ’†๐Ÿป ๐Ÿ’†๐Ÿปโ€โ™‚๏ธ ๐Ÿ•ด๐Ÿป ๐Ÿ’ƒ๐Ÿป ๐Ÿ•บ๐Ÿป ๐Ÿšถ๐Ÿปโ€โ™€๏ธ ๐Ÿšถ๐Ÿป ๐Ÿƒ๐Ÿปโ€โ™€๏ธ ๐Ÿƒ๐Ÿป ๐Ÿคฒ๐Ÿป ๐Ÿ‘๐Ÿป ๐Ÿ™Œ๐Ÿป ๐Ÿ‘๐Ÿป ๐Ÿ™๐Ÿป ๐Ÿ‘๐Ÿป ๐Ÿ‘Ž๐Ÿป ๐Ÿ‘Š๐Ÿป โœŠ๐Ÿป ๐Ÿค›๐Ÿป ๐Ÿคœ๐Ÿป ๐Ÿคž๐Ÿป โœŒ๐Ÿป ๐ŸคŸ๐Ÿป ๐Ÿค˜๐Ÿป ๐Ÿ‘Œ๐Ÿป ๐Ÿ‘ˆ๐Ÿป ๐Ÿ‘‰๐Ÿป ๐Ÿ‘†๐Ÿป ๐Ÿ‘‡๐Ÿป โ˜๐Ÿป โœ‹๐Ÿป ๐Ÿคš๐Ÿป ๐Ÿ–๐Ÿป ๐Ÿ––๐Ÿป ๐Ÿ‘‹๐Ÿป ๐Ÿค™๐Ÿป ๐Ÿ’ช๐Ÿป ๐Ÿ–•๐Ÿป โœ๐Ÿป ๐Ÿคณ๐Ÿป ๐Ÿ’…๐Ÿป ๐Ÿ‘‚๐Ÿป ๐Ÿ‘ƒ๐Ÿป +๐Ÿ‘ถ๐Ÿผ ๐Ÿ‘ฆ๐Ÿผ ๐Ÿ‘ง๐Ÿผ ๐Ÿ‘จ๐Ÿผ ๐Ÿ‘ฉ๐Ÿผ ๐Ÿ‘ฑ๐Ÿผโ€โ™€๏ธ ๐Ÿ‘ฑ๐Ÿผ ๐Ÿ‘ด๐Ÿผ ๐Ÿ‘ต๐Ÿผ ๐Ÿ‘ฒ๐Ÿผ ๐Ÿ‘ณ๐Ÿผโ€โ™€๏ธ ๐Ÿ‘ณ๐Ÿผ ๐Ÿ‘ฎ๐Ÿผโ€โ™€๏ธ ๐Ÿ‘ฎ๐Ÿผ ๐Ÿ‘ท๐Ÿผโ€โ™€๏ธ ๐Ÿ‘ท๐Ÿผ ๐Ÿ’‚๐Ÿผโ€โ™€๏ธ ๐Ÿ’‚๐Ÿผ ๐Ÿ•ต๐Ÿผโ€โ™€๏ธ ๐Ÿ•ต๐Ÿผ ๐Ÿ‘ฉ๐Ÿผโ€โš•๏ธ ๐Ÿ‘จ๐Ÿผโ€โš•๏ธ ๐Ÿ‘ฉ๐Ÿผโ€๐ŸŒพ ๐Ÿ‘จ๐Ÿผโ€๐ŸŒพ ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿณ ๐Ÿ‘จ๐Ÿผโ€๐Ÿณ ๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽ“ ๐Ÿ‘จ๐Ÿผโ€๐ŸŽ“ ๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽค ๐Ÿ‘จ๐Ÿผโ€๐ŸŽค ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿซ ๐Ÿ‘จ๐Ÿผโ€๐Ÿซ ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿญ ๐Ÿ‘จ๐Ÿผโ€๐Ÿญ ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ’ป ๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ป ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ’ผ ๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ผ ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ”ง ๐Ÿ‘จ๐Ÿผโ€๐Ÿ”ง ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿ”ฌ ๐Ÿ‘จ๐Ÿผโ€๐Ÿ”ฌ ๐Ÿ‘ฉ๐Ÿผโ€๐ŸŽจ ๐Ÿ‘จ๐Ÿผโ€๐ŸŽจ ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿš’ ๐Ÿ‘จ๐Ÿผโ€๐Ÿš’ ๐Ÿ‘ฉ๐Ÿผโ€โœˆ๏ธ ๐Ÿ‘จ๐Ÿผโ€โœˆ๏ธ ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿš€ ๐Ÿ‘จ๐Ÿผโ€๐Ÿš€ ๐Ÿ‘ฉ๐Ÿผโ€โš–๏ธ ๐Ÿ‘จ๐Ÿผโ€โš–๏ธ ๐Ÿคถ๐Ÿผ ๐ŸŽ…๐Ÿผ ๐Ÿ‘ธ๐Ÿผ ๐Ÿคด๐Ÿผ ๐Ÿ‘ฐ๐Ÿผ ๐Ÿคต๐Ÿผ ๐Ÿ‘ผ๐Ÿผ ๐Ÿคฐ๐Ÿผ ๐Ÿ™‡๐Ÿผโ€โ™€๏ธ ๐Ÿ™‡๐Ÿผ ๐Ÿ’๐Ÿผ ๐Ÿ’๐Ÿผโ€โ™‚๏ธ ๐Ÿ™…๐Ÿผ ๐Ÿ™…๐Ÿผโ€โ™‚๏ธ ๐Ÿ™†๐Ÿผ ๐Ÿ™†๐Ÿผโ€โ™‚๏ธ ๐Ÿ™‹๐Ÿผ ๐Ÿ™‹๐Ÿผโ€โ™‚๏ธ ๐Ÿคฆ๐Ÿผโ€โ™€๏ธ ๐Ÿคฆ๐Ÿผโ€โ™‚๏ธ ๐Ÿคท๐Ÿผโ€โ™€๏ธ ๐Ÿคท๐Ÿผโ€โ™‚๏ธ ๐Ÿ™Ž๐Ÿผ ๐Ÿ™Ž๐Ÿผโ€โ™‚๏ธ ๐Ÿ™๐Ÿผ ๐Ÿ™๐Ÿผโ€โ™‚๏ธ ๐Ÿ’‡๐Ÿผ ๐Ÿ’‡๐Ÿผโ€โ™‚๏ธ ๐Ÿ’†๐Ÿผ ๐Ÿ’†๐Ÿผโ€โ™‚๏ธ ๐Ÿ•ด๐Ÿผ ๐Ÿ’ƒ๐Ÿผ ๐Ÿ•บ๐Ÿผ ๐Ÿšถ๐Ÿผโ€โ™€๏ธ ๐Ÿšถ๐Ÿผ ๐Ÿƒ๐Ÿผโ€โ™€๏ธ ๐Ÿƒ๐Ÿผ ๐Ÿคฒ๐Ÿผ ๐Ÿ‘๐Ÿผ ๐Ÿ™Œ๐Ÿผ ๐Ÿ‘๐Ÿผ ๐Ÿ™๐Ÿผ ๐Ÿ‘๐Ÿผ ๐Ÿ‘Ž๐Ÿผ ๐Ÿ‘Š๐Ÿผ โœŠ๐Ÿผ ๐Ÿค›๐Ÿผ ๐Ÿคœ๐Ÿผ ๐Ÿคž๐Ÿผ โœŒ๐Ÿผ ๐ŸคŸ๐Ÿผ ๐Ÿค˜๐Ÿผ ๐Ÿ‘Œ๐Ÿผ ๐Ÿ‘ˆ๐Ÿผ ๐Ÿ‘‰๐Ÿผ ๐Ÿ‘†๐Ÿผ ๐Ÿ‘‡๐Ÿผ โ˜๐Ÿผ โœ‹๐Ÿผ ๐Ÿคš๐Ÿผ ๐Ÿ–๐Ÿผ ๐Ÿ––๐Ÿผ ๐Ÿ‘‹๐Ÿผ ๐Ÿค™๐Ÿผ ๐Ÿ’ช๐Ÿผ ๐Ÿ–•๐Ÿผ โœ๐Ÿผ ๐Ÿคณ๐Ÿผ ๐Ÿ’…๐Ÿผ ๐Ÿ‘‚๐Ÿผ ๐Ÿ‘ƒ๐Ÿผ +๐Ÿ‘ถ๐Ÿฝ ๐Ÿ‘ฆ๐Ÿฝ ๐Ÿ‘ง๐Ÿฝ ๐Ÿ‘จ๐Ÿฝ ๐Ÿ‘ฉ๐Ÿฝ ๐Ÿ‘ฑ๐Ÿฝโ€โ™€๏ธ ๐Ÿ‘ฑ๐Ÿฝ ๐Ÿ‘ด๐Ÿฝ ๐Ÿ‘ต๐Ÿฝ ๐Ÿ‘ฒ๐Ÿฝ ๐Ÿ‘ณ๐Ÿฝโ€โ™€๏ธ ๐Ÿ‘ณ๐Ÿฝ ๐Ÿ‘ฎ๐Ÿฝโ€โ™€๏ธ ๐Ÿ‘ฎ๐Ÿฝ ๐Ÿ‘ท๐Ÿฝโ€โ™€๏ธ ๐Ÿ‘ท๐Ÿฝ ๐Ÿ’‚๐Ÿฝโ€โ™€๏ธ ๐Ÿ’‚๐Ÿฝ ๐Ÿ•ต๐Ÿฝโ€โ™€๏ธ ๐Ÿ•ต๐Ÿฝ ๐Ÿ‘ฉ๐Ÿฝโ€โš•๏ธ ๐Ÿ‘จ๐Ÿฝโ€โš•๏ธ ๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŒพ ๐Ÿ‘จ๐Ÿฝโ€๐ŸŒพ ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿณ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿณ ๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽ“ ๐Ÿ‘จ๐Ÿฝโ€๐ŸŽ“ ๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽค ๐Ÿ‘จ๐Ÿฝโ€๐ŸŽค ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿซ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿซ ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿญ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿญ ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป ๐Ÿ‘จ๐Ÿฝโ€๐Ÿ’ป ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ผ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿ’ผ ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ”ง ๐Ÿ‘จ๐Ÿฝโ€๐Ÿ”ง ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ”ฌ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿ”ฌ ๐Ÿ‘ฉ๐Ÿฝโ€๐ŸŽจ ๐Ÿ‘จ๐Ÿฝโ€๐ŸŽจ ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿš’ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿš’ ๐Ÿ‘ฉ๐Ÿฝโ€โœˆ๏ธ ๐Ÿ‘จ๐Ÿฝโ€โœˆ๏ธ ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿš€ ๐Ÿ‘จ๐Ÿฝโ€๐Ÿš€ ๐Ÿ‘ฉ๐Ÿฝโ€โš–๏ธ ๐Ÿ‘จ๐Ÿฝโ€โš–๏ธ ๐Ÿคถ๐Ÿฝ ๐ŸŽ…๐Ÿฝ ๐Ÿ‘ธ๐Ÿฝ ๐Ÿคด๐Ÿฝ ๐Ÿ‘ฐ๐Ÿฝ ๐Ÿคต๐Ÿฝ ๐Ÿ‘ผ๐Ÿฝ ๐Ÿคฐ๐Ÿฝ ๐Ÿ™‡๐Ÿฝโ€โ™€๏ธ ๐Ÿ™‡๐Ÿฝ ๐Ÿ’๐Ÿฝ ๐Ÿ’๐Ÿฝโ€โ™‚๏ธ ๐Ÿ™…๐Ÿฝ ๐Ÿ™…๐Ÿฝโ€โ™‚๏ธ ๐Ÿ™†๐Ÿฝ ๐Ÿ™†๐Ÿฝโ€โ™‚๏ธ ๐Ÿ™‹๐Ÿฝ ๐Ÿ™‹๐Ÿฝโ€โ™‚๏ธ ๐Ÿคฆ๐Ÿฝโ€โ™€๏ธ ๐Ÿคฆ๐Ÿฝโ€โ™‚๏ธ ๐Ÿคท๐Ÿฝโ€โ™€๏ธ ๐Ÿคท๐Ÿฝโ€โ™‚๏ธ ๐Ÿ™Ž๐Ÿฝ ๐Ÿ™Ž๐Ÿฝโ€โ™‚๏ธ ๐Ÿ™๐Ÿฝ ๐Ÿ™๐Ÿฝโ€โ™‚๏ธ ๐Ÿ’‡๐Ÿฝ ๐Ÿ’‡๐Ÿฝโ€โ™‚๏ธ ๐Ÿ’†๐Ÿฝ ๐Ÿ’†๐Ÿฝโ€โ™‚๏ธ ๐Ÿ•ด๐Ÿผ ๐Ÿ’ƒ๐Ÿฝ ๐Ÿ•บ๐Ÿฝ ๐Ÿšถ๐Ÿฝโ€โ™€๏ธ ๐Ÿšถ๐Ÿฝ ๐Ÿƒ๐Ÿฝโ€โ™€๏ธ ๐Ÿƒ๐Ÿฝ ๐Ÿคฒ๐Ÿฝ ๐Ÿ‘๐Ÿฝ ๐Ÿ™Œ๐Ÿฝ ๐Ÿ‘๐Ÿฝ ๐Ÿ™๐Ÿฝ ๐Ÿ‘๐Ÿฝ ๐Ÿ‘Ž๐Ÿฝ ๐Ÿ‘Š๐Ÿฝ โœŠ๐Ÿฝ ๐Ÿค›๐Ÿฝ ๐Ÿคœ๐Ÿฝ ๐Ÿคž๐Ÿฝ โœŒ๐Ÿฝ ๐ŸคŸ๐Ÿฝ ๐Ÿค˜๐Ÿฝ ๐Ÿ‘Œ๐Ÿฝ ๐Ÿ‘ˆ๐Ÿฝ ๐Ÿ‘‰๐Ÿฝ ๐Ÿ‘†๐Ÿฝ ๐Ÿ‘‡๐Ÿฝ โ˜๐Ÿฝ โœ‹๐Ÿฝ ๐Ÿคš๐Ÿฝ ๐Ÿ–๐Ÿฝ ๐Ÿ––๐Ÿฝ ๐Ÿ‘‹๐Ÿฝ ๐Ÿค™๐Ÿฝ ๐Ÿ’ช๐Ÿฝ ๐Ÿ–•๐Ÿฝ โœ๐Ÿฝ ๐Ÿคณ๐Ÿฝ ๐Ÿ’…๐Ÿฝ ๐Ÿ‘‚๐Ÿฝ ๐Ÿ‘ƒ๐Ÿฝ +๐Ÿ‘ถ๐Ÿพ ๐Ÿ‘ฆ๐Ÿพ ๐Ÿ‘ง๐Ÿพ ๐Ÿ‘จ๐Ÿพ ๐Ÿ‘ฉ๐Ÿพ ๐Ÿ‘ฑ๐Ÿพโ€โ™€๏ธ ๐Ÿ‘ฑ๐Ÿพ ๐Ÿ‘ด๐Ÿพ ๐Ÿ‘ต๐Ÿพ ๐Ÿ‘ฒ๐Ÿพ ๐Ÿ‘ณ๐Ÿพโ€โ™€๏ธ ๐Ÿ‘ณ๐Ÿพ ๐Ÿ‘ฎ๐Ÿพโ€โ™€๏ธ ๐Ÿ‘ฎ๐Ÿพ ๐Ÿ‘ท๐Ÿพโ€โ™€๏ธ ๐Ÿ‘ท๐Ÿพ ๐Ÿ’‚๐Ÿพโ€โ™€๏ธ ๐Ÿ’‚๐Ÿพ ๐Ÿ•ต๐Ÿพโ€โ™€๏ธ ๐Ÿ•ต๐Ÿพ ๐Ÿ‘ฉ๐Ÿพโ€โš•๏ธ ๐Ÿ‘จ๐Ÿพโ€โš•๏ธ ๐Ÿ‘ฉ๐Ÿพโ€๐ŸŒพ ๐Ÿ‘จ๐Ÿพโ€๐ŸŒพ ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿณ ๐Ÿ‘จ๐Ÿพโ€๐Ÿณ ๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽ“ ๐Ÿ‘จ๐Ÿพโ€๐ŸŽ“ ๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽค ๐Ÿ‘จ๐Ÿพโ€๐ŸŽค ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿซ ๐Ÿ‘จ๐Ÿพโ€๐Ÿซ ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿญ ๐Ÿ‘จ๐Ÿพโ€๐Ÿญ ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ป ๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ป ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ผ ๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ผ ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ”ง ๐Ÿ‘จ๐Ÿพโ€๐Ÿ”ง ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ”ฌ ๐Ÿ‘จ๐Ÿพโ€๐Ÿ”ฌ ๐Ÿ‘ฉ๐Ÿพโ€๐ŸŽจ ๐Ÿ‘จ๐Ÿพโ€๐ŸŽจ ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿš’ ๐Ÿ‘จ๐Ÿพโ€๐Ÿš’ ๐Ÿ‘ฉ๐Ÿพโ€โœˆ๏ธ ๐Ÿ‘จ๐Ÿพโ€โœˆ๏ธ ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿš€ ๐Ÿ‘จ๐Ÿพโ€๐Ÿš€ ๐Ÿ‘ฉ๐Ÿพโ€โš–๏ธ ๐Ÿ‘จ๐Ÿพโ€โš–๏ธ ๐Ÿคถ๐Ÿพ ๐ŸŽ…๐Ÿพ ๐Ÿ‘ธ๐Ÿพ ๐Ÿคด๐Ÿพ ๐Ÿ‘ฐ๐Ÿพ ๐Ÿคต๐Ÿพ ๐Ÿ‘ผ๐Ÿพ ๐Ÿคฐ๐Ÿพ ๐Ÿ™‡๐Ÿพโ€โ™€๏ธ ๐Ÿ™‡๐Ÿพ ๐Ÿ’๐Ÿพ ๐Ÿ’๐Ÿพโ€โ™‚๏ธ ๐Ÿ™…๐Ÿพ ๐Ÿ™…๐Ÿพโ€โ™‚๏ธ ๐Ÿ™†๐Ÿพ ๐Ÿ™†๐Ÿพโ€โ™‚๏ธ ๐Ÿ™‹๐Ÿพ ๐Ÿ™‹๐Ÿพโ€โ™‚๏ธ ๐Ÿคฆ๐Ÿพโ€โ™€๏ธ ๐Ÿคฆ๐Ÿพโ€โ™‚๏ธ ๐Ÿคท๐Ÿพโ€โ™€๏ธ ๐Ÿคท๐Ÿพโ€โ™‚๏ธ ๐Ÿ™Ž๐Ÿพ ๐Ÿ™Ž๐Ÿพโ€โ™‚๏ธ ๐Ÿ™๐Ÿพ ๐Ÿ™๐Ÿพโ€โ™‚๏ธ ๐Ÿ’‡๐Ÿพ ๐Ÿ’‡๐Ÿพโ€โ™‚๏ธ ๐Ÿ’†๐Ÿพ ๐Ÿ’†๐Ÿพโ€โ™‚๏ธ ๐Ÿ•ด๐Ÿพ ๐Ÿ’ƒ๐Ÿพ ๐Ÿ•บ๐Ÿพ ๐Ÿšถ๐Ÿพโ€โ™€๏ธ ๐Ÿšถ๐Ÿพ ๐Ÿƒ๐Ÿพโ€โ™€๏ธ ๐Ÿƒ๐Ÿพ ๐Ÿคฒ๐Ÿพ ๐Ÿ‘๐Ÿพ ๐Ÿ™Œ๐Ÿพ ๐Ÿ‘๐Ÿพ ๐Ÿ™๐Ÿพ ๐Ÿ‘๐Ÿพ ๐Ÿ‘Ž๐Ÿพ ๐Ÿ‘Š๐Ÿพ โœŠ๐Ÿพ ๐Ÿค›๐Ÿพ ๐Ÿคœ๐Ÿพ ๐Ÿคž๐Ÿพ โœŒ๐Ÿพ ๐ŸคŸ๐Ÿพ ๐Ÿค˜๐Ÿพ ๐Ÿ‘Œ๐Ÿพ ๐Ÿ‘ˆ๐Ÿพ ๐Ÿ‘‰๐Ÿพ ๐Ÿ‘†๐Ÿพ ๐Ÿ‘‡๐Ÿพ โ˜๐Ÿพ โœ‹๐Ÿพ ๐Ÿคš๐Ÿพ ๐Ÿ–๐Ÿพ ๐Ÿ––๐Ÿพ ๐Ÿ‘‹๐Ÿพ ๐Ÿค™๐Ÿพ ๐Ÿ’ช๐Ÿพ ๐Ÿ–•๐Ÿพ โœ๐Ÿพ ๐Ÿคณ๐Ÿพ ๐Ÿ’…๐Ÿพ ๐Ÿ‘‚๐Ÿพ ๐Ÿ‘ƒ๐Ÿพ +๐Ÿ‘ถ๐Ÿฟ ๐Ÿ‘ฆ๐Ÿฟ ๐Ÿ‘ง๐Ÿฟ ๐Ÿ‘จ๐Ÿฟ ๐Ÿ‘ฉ๐Ÿฟ ๐Ÿ‘ฑ๐Ÿฟโ€โ™€๏ธ ๐Ÿ‘ฑ๐Ÿฟ ๐Ÿ‘ด๐Ÿฟ ๐Ÿ‘ต๐Ÿฟ ๐Ÿ‘ฒ๐Ÿฟ ๐Ÿ‘ณ๐Ÿฟโ€โ™€๏ธ ๐Ÿ‘ณ๐Ÿฟ ๐Ÿ‘ฎ๐Ÿฟโ€โ™€๏ธ ๐Ÿ‘ฎ๐Ÿฟ ๐Ÿ‘ท๐Ÿฟโ€โ™€๏ธ ๐Ÿ‘ท๐Ÿฟ ๐Ÿ’‚๐Ÿฟโ€โ™€๏ธ ๐Ÿ’‚๐Ÿฟ ๐Ÿ•ต๐Ÿฟโ€โ™€๏ธ ๐Ÿ•ต๐Ÿฟ ๐Ÿ‘ฉ๐Ÿฟโ€โš•๏ธ ๐Ÿ‘จ๐Ÿฟโ€โš•๏ธ ๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŒพ ๐Ÿ‘จ๐Ÿฟโ€๐ŸŒพ ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿณ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿณ ๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽ“ ๐Ÿ‘จ๐Ÿฟโ€๐ŸŽ“ ๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽค ๐Ÿ‘จ๐Ÿฟโ€๐ŸŽค ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿซ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿซ ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿญ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿญ ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ’ป ๐Ÿ‘จ๐Ÿฟโ€๐Ÿ’ป ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ’ผ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿ’ผ ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ”ง ๐Ÿ‘จ๐Ÿฟโ€๐Ÿ”ง ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿ”ฌ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿ”ฌ ๐Ÿ‘ฉ๐Ÿฟโ€๐ŸŽจ ๐Ÿ‘จ๐Ÿฟโ€๐ŸŽจ ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿš’ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿš’ ๐Ÿ‘ฉ๐Ÿฟโ€โœˆ๏ธ ๐Ÿ‘จ๐Ÿฟโ€โœˆ๏ธ ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿš€ ๐Ÿ‘จ๐Ÿฟโ€๐Ÿš€ ๐Ÿ‘ฉ๐Ÿฟโ€โš–๏ธ ๐Ÿ‘จ๐Ÿฟโ€โš–๏ธ ๐Ÿคถ๐Ÿฟ ๐ŸŽ…๐Ÿฟ ๐Ÿ‘ธ๐Ÿฟ ๐Ÿคด๐Ÿฟ ๐Ÿ‘ฐ๐Ÿฟ ๐Ÿคต๐Ÿฟ ๐Ÿ‘ผ๐Ÿฟ ๐Ÿคฐ๐Ÿฟ ๐Ÿ™‡๐Ÿฟโ€โ™€๏ธ ๐Ÿ™‡๐Ÿฟ ๐Ÿ’๐Ÿฟ ๐Ÿ’๐Ÿฟโ€โ™‚๏ธ ๐Ÿ™…๐Ÿฟ ๐Ÿ™…๐Ÿฟโ€โ™‚๏ธ ๐Ÿ™†๐Ÿฟ ๐Ÿ™†๐Ÿฟโ€โ™‚๏ธ ๐Ÿ™‹๐Ÿฟ ๐Ÿ™‹๐Ÿฟโ€โ™‚๏ธ ๐Ÿคฆ๐Ÿฟโ€โ™€๏ธ ๐Ÿคฆ๐Ÿฟโ€โ™‚๏ธ ๐Ÿคท๐Ÿฟโ€โ™€๏ธ ๐Ÿคท๐Ÿฟโ€โ™‚๏ธ ๐Ÿ™Ž๐Ÿฟ ๐Ÿ™Ž๐Ÿฟโ€โ™‚๏ธ ๐Ÿ™๐Ÿฟ ๐Ÿ™๐Ÿฟโ€โ™‚๏ธ ๐Ÿ’‡๐Ÿฟ ๐Ÿ’‡๐Ÿฟโ€โ™‚๏ธ ๐Ÿ’†๐Ÿฟ ๐Ÿ’†๐Ÿฟโ€โ™‚๏ธ ๐Ÿ•ด๐Ÿฟ ๐Ÿ’ƒ๐Ÿฟ ๐Ÿ•บ๐Ÿฟ ๐Ÿšถ๐Ÿฟโ€โ™€๏ธ ๐Ÿšถ๐Ÿฟ ๐Ÿƒ๐Ÿฟโ€โ™€๏ธ ๐Ÿƒ๐Ÿฟ ๐Ÿคฒ๐Ÿฟ ๐Ÿ‘๐Ÿฟ ๐Ÿ™Œ๐Ÿฟ ๐Ÿ‘๐Ÿฟ ๐Ÿ™๐Ÿฟ ๐Ÿ‘๐Ÿฟ ๐Ÿ‘Ž๐Ÿฟ ๐Ÿ‘Š๐Ÿฟ โœŠ๐Ÿฟ ๐Ÿค›๐Ÿฟ ๐Ÿคœ๐Ÿฟ ๐Ÿคž๐Ÿฟ โœŒ๐Ÿฟ ๐ŸคŸ๐Ÿฟ ๐Ÿค˜๐Ÿฟ ๐Ÿ‘Œ๐Ÿฟ ๐Ÿ‘ˆ๐Ÿฟ ๐Ÿ‘‰๐Ÿฟ ๐Ÿ‘†๐Ÿฟ ๐Ÿ‘‡๐Ÿฟ โ˜๐Ÿฟ โœ‹๐Ÿฟ ๐Ÿคš๐Ÿฟ ๐Ÿ–๐Ÿฟ ๐Ÿ––๐Ÿฟ ๐Ÿ‘‹๐Ÿฟ ๐Ÿค™๐Ÿฟ ๐Ÿ’ช๐Ÿฟ ๐Ÿ–•๐Ÿฟ โœ๐Ÿฟ ๐Ÿคณ๐Ÿฟ ๐Ÿ’…๐Ÿฟ ๐Ÿ‘‚๐Ÿฟ ๐Ÿ‘ƒ๐Ÿฟ +๐Ÿถ ๐Ÿฑ ๐Ÿญ ๐Ÿน ๐Ÿฐ ๐ŸฆŠ ๐Ÿฆ ๐Ÿป ๐Ÿผ ๐Ÿฆ˜ ๐Ÿฆก ๐Ÿจ ๐Ÿฏ ๐Ÿฆ ๐Ÿฎ ๐Ÿท ๐Ÿฝ ๐Ÿธ ๐Ÿต ๐Ÿ™ˆ ๐Ÿ™‰ ๐Ÿ™Š ๐Ÿ’ ๐Ÿ” ๐Ÿง ๐Ÿฆ ๐Ÿค ๐Ÿฃ ๐Ÿฅ ๐Ÿฆ† ๐Ÿฆข ๐Ÿฆ… ๐Ÿฆ‰ ๐Ÿฆš ๐Ÿฆœ ๐Ÿฆ‡ ๐Ÿบ ๐Ÿ— ๐Ÿด ๐Ÿฆ„ ๐Ÿ ๐Ÿ› ๐Ÿฆ‹ ๐ŸŒ ๐Ÿš ๐Ÿž ๐Ÿœ ๐Ÿฆ— ๐Ÿ•ท ๐Ÿ•ธ ๐Ÿฆ‚ ๐ŸฆŸ ๐Ÿฆ  ๐Ÿข ๐Ÿ ๐ŸฆŽ ๐Ÿฆ– ๐Ÿฆ• ๐Ÿ™ ๐Ÿฆ‘ ๐Ÿฆ ๐Ÿฆ€ ๐Ÿก ๐Ÿ  ๐ŸŸ ๐Ÿฌ ๐Ÿณ ๐Ÿ‹ ๐Ÿฆˆ ๐ŸŠ ๐Ÿ… ๐Ÿ† ๐Ÿฆ“ ๐Ÿฆ ๐Ÿ˜ ๐Ÿฆ ๐Ÿฆ› ๐Ÿช ๐Ÿซ ๐Ÿฆ™ ๐Ÿฆ’ ๐Ÿƒ ๐Ÿ‚ ๐Ÿ„ ๐ŸŽ ๐Ÿ– ๐Ÿ ๐Ÿ‘ ๐Ÿ ๐ŸฆŒ ๐Ÿ• ๐Ÿฉ ๐Ÿˆ ๐Ÿ“ ๐Ÿฆƒ ๐Ÿ•Š ๐Ÿ‡ ๐Ÿ ๐Ÿ€ ๐Ÿฟ ๐Ÿฆ” ๐Ÿพ ๐Ÿ‰ ๐Ÿฒ ๐ŸŒต ๐ŸŽ„ ๐ŸŒฒ ๐ŸŒณ ๐ŸŒด ๐ŸŒฑ ๐ŸŒฟ โ˜˜๏ธ ๐Ÿ€ ๐ŸŽ ๐ŸŽ‹ ๐Ÿƒ ๐Ÿ‚ ๐Ÿ ๐Ÿ„ ๐ŸŒพ ๐Ÿ’ ๐ŸŒท ๐ŸŒน ๐Ÿฅ€ ๐ŸŒบ ๐ŸŒธ ๐ŸŒผ ๐ŸŒป ๐ŸŒž ๐ŸŒ ๐ŸŒ› ๐ŸŒœ ๐ŸŒš ๐ŸŒ• ๐ŸŒ– ๐ŸŒ— ๐ŸŒ˜ ๐ŸŒ‘ ๐ŸŒ’ ๐ŸŒ“ ๐ŸŒ” ๐ŸŒ™ ๐ŸŒŽ ๐ŸŒ ๐ŸŒ ๐Ÿ’ซ โญ๏ธ ๐ŸŒŸ โœจ โšก๏ธ โ˜„๏ธ ๐Ÿ’ฅ ๐Ÿ”ฅ ๐ŸŒช ๐ŸŒˆ โ˜€๏ธ ๐ŸŒค โ›…๏ธ ๐ŸŒฅ โ˜๏ธ ๐ŸŒฆ ๐ŸŒง โ›ˆ ๐ŸŒฉ ๐ŸŒจ โ„๏ธ โ˜ƒ๏ธ โ›„๏ธ ๐ŸŒฌ ๐Ÿ’จ ๐Ÿ’ง ๐Ÿ’ฆ โ˜”๏ธ โ˜‚๏ธ ๐ŸŒŠ ๐ŸŒซ +๐Ÿ ๐ŸŽ ๐Ÿ ๐ŸŠ ๐Ÿ‹ ๐ŸŒ ๐Ÿ‰ ๐Ÿ‡ ๐Ÿ“ ๐Ÿˆ ๐Ÿ’ ๐Ÿ‘ ๐Ÿ ๐Ÿฅญ ๐Ÿฅฅ ๐Ÿฅ ๐Ÿ… ๐Ÿ† ๐Ÿฅ‘ ๐Ÿฅฆ ๐Ÿฅ’ ๐Ÿฅฌ ๐ŸŒถ ๐ŸŒฝ ๐Ÿฅ• ๐Ÿฅ” ๐Ÿ  ๐Ÿฅ ๐Ÿž ๐Ÿฅ– ๐Ÿฅจ ๐Ÿฅฏ ๐Ÿง€ ๐Ÿฅš ๐Ÿณ ๐Ÿฅž ๐Ÿฅ“ ๐Ÿฅฉ ๐Ÿ— ๐Ÿ– ๐ŸŒญ ๐Ÿ” ๐ŸŸ ๐Ÿ• ๐Ÿฅช ๐Ÿฅ™ ๐ŸŒฎ ๐ŸŒฏ ๐Ÿฅ— ๐Ÿฅ˜ ๐Ÿฅซ ๐Ÿ ๐Ÿœ ๐Ÿฒ ๐Ÿ› ๐Ÿฃ ๐Ÿฑ ๐ŸฅŸ ๐Ÿค ๐Ÿ™ ๐Ÿš ๐Ÿ˜ ๐Ÿฅ ๐Ÿฅฎ ๐Ÿฅ  ๐Ÿข ๐Ÿก ๐Ÿง ๐Ÿจ ๐Ÿฆ ๐Ÿฅง ๐Ÿฐ ๐ŸŽ‚ ๐Ÿฎ ๐Ÿญ ๐Ÿฌ ๐Ÿซ ๐Ÿฟ ๐Ÿง‚ ๐Ÿฉ ๐Ÿช ๐ŸŒฐ ๐Ÿฅœ ๐Ÿฏ ๐Ÿฅ› ๐Ÿผ โ˜•๏ธ ๐Ÿต ๐Ÿฅค ๐Ÿถ ๐Ÿบ ๐Ÿป ๐Ÿฅ‚ ๐Ÿท ๐Ÿฅƒ ๐Ÿธ ๐Ÿน ๐Ÿพ ๐Ÿฅ„ ๐Ÿด ๐Ÿฝ ๐Ÿฅฃ ๐Ÿฅก ๐Ÿฅข +โšฝ๏ธ ๐Ÿ€ ๐Ÿˆ โšพ๏ธ ๐ŸฅŽ ๐Ÿ ๐Ÿ‰ ๐ŸŽพ ๐Ÿฅ ๐ŸŽฑ ๐Ÿ“ ๐Ÿธ ๐Ÿฅ… ๐Ÿ’ ๐Ÿ‘ ๐Ÿฅ ๐Ÿ โ›ณ๏ธ ๐Ÿน ๐ŸŽฃ ๐ŸฅŠ ๐Ÿฅ‹ ๐ŸŽฝ โ›ธ ๐ŸฅŒ ๐Ÿ›ท ๐Ÿ›น ๐ŸŽฟ โ›ท ๐Ÿ‚ ๐Ÿ‹๏ธโ€โ™€๏ธ ๐Ÿ‹๐Ÿปโ€โ™€๏ธ ๐Ÿ‹๐Ÿผโ€โ™€๏ธ ๐Ÿ‹๐Ÿฝโ€โ™€๏ธ ๐Ÿ‹๐Ÿพโ€โ™€๏ธ ๐Ÿ‹๐Ÿฟโ€โ™€๏ธ ๐Ÿ‹๏ธโ€โ™‚๏ธ ๐Ÿ‹๐Ÿปโ€โ™‚๏ธ ๐Ÿ‹๐Ÿผโ€โ™‚๏ธ ๐Ÿ‹๐Ÿฝโ€โ™‚๏ธ ๐Ÿ‹๐Ÿพโ€โ™‚๏ธ ๐Ÿ‹๐Ÿฟโ€โ™‚๏ธ ๐Ÿคผโ€โ™€๏ธ ๐Ÿคผโ€โ™‚๏ธ ๐Ÿคธโ€โ™€๏ธ ๐Ÿคธ๐Ÿปโ€โ™€๏ธ ๐Ÿคธ๐Ÿผโ€โ™€๏ธ ๐Ÿคธ๐Ÿฝโ€โ™€๏ธ ๐Ÿคธ๐Ÿพโ€โ™€๏ธ ๐Ÿคธ๐Ÿฟโ€โ™€๏ธ ๐Ÿคธโ€โ™‚๏ธ ๐Ÿคธ๐Ÿปโ€โ™‚๏ธ ๐Ÿคธ๐Ÿผโ€โ™‚๏ธ ๐Ÿคธ๐Ÿฝโ€โ™‚๏ธ ๐Ÿคธ๐Ÿพโ€โ™‚๏ธ ๐Ÿคธ๐Ÿฟโ€โ™‚๏ธ โ›น๏ธโ€โ™€๏ธ โ›น๐Ÿปโ€โ™€๏ธ โ›น๐Ÿผโ€โ™€๏ธ โ›น๐Ÿฝโ€โ™€๏ธ โ›น๐Ÿพโ€โ™€๏ธ โ›น๐Ÿฟโ€โ™€๏ธ โ›น๏ธโ€โ™‚๏ธ โ›น๐Ÿปโ€โ™‚๏ธ โ›น๐Ÿผโ€โ™‚๏ธ โ›น๐Ÿฝโ€โ™‚๏ธ โ›น๐Ÿพโ€โ™‚๏ธ โ›น๐Ÿฟโ€โ™‚๏ธ ๐Ÿคบ ๐Ÿคพโ€โ™€๏ธ ๐Ÿคพ๐Ÿปโ€โ™€๏ธ ๐Ÿคพ๐Ÿผโ€โ™€๏ธ ๐Ÿคพ๐Ÿพโ€โ™€๏ธ ๐Ÿคพ๐Ÿพโ€โ™€๏ธ ๐Ÿคพ๐Ÿฟโ€โ™€๏ธ ๐Ÿคพโ€โ™‚๏ธ ๐Ÿคพ๐Ÿปโ€โ™‚๏ธ ๐Ÿคพ๐Ÿผโ€โ™‚๏ธ ๐Ÿคพ๐Ÿฝโ€โ™‚๏ธ ๐Ÿคพ๐Ÿพโ€โ™‚๏ธ ๐Ÿคพ๐Ÿฟโ€โ™‚๏ธ ๐ŸŒ๏ธโ€โ™€๏ธ ๐ŸŒ๐Ÿปโ€โ™€๏ธ ๐ŸŒ๐Ÿผโ€โ™€๏ธ ๐ŸŒ๐Ÿฝโ€โ™€๏ธ ๐ŸŒ๐Ÿพโ€โ™€๏ธ ๐ŸŒ๐Ÿฟโ€โ™€๏ธ ๐ŸŒ๏ธโ€โ™‚๏ธ ๐ŸŒ๐Ÿปโ€โ™‚๏ธ ๐ŸŒ๐Ÿผโ€โ™‚๏ธ ๐ŸŒ๐Ÿฝโ€โ™‚๏ธ ๐ŸŒ๐Ÿพโ€โ™‚๏ธ ๐ŸŒ๐Ÿฟโ€โ™‚๏ธ ๐Ÿ‡ ๐Ÿ‡๐Ÿป ๐Ÿ‡๐Ÿผ ๐Ÿ‡๐Ÿฝ ๐Ÿ‡๐Ÿพ ๐Ÿ‡๐Ÿฟ ๐Ÿง˜โ€โ™€๏ธ ๐Ÿง˜๐Ÿปโ€โ™€๏ธ ๐Ÿง˜๐Ÿผโ€โ™€๏ธ ๐Ÿง˜๐Ÿฝโ€โ™€๏ธ ๐Ÿง˜๐Ÿพโ€โ™€๏ธ ๐Ÿง˜๐Ÿฟโ€โ™€๏ธ ๐Ÿง˜โ€โ™‚๏ธ ๐Ÿง˜๐Ÿปโ€โ™‚๏ธ ๐Ÿง˜๐Ÿผโ€โ™‚๏ธ ๐Ÿง˜๐Ÿฝโ€โ™‚๏ธ ๐Ÿง˜๐Ÿพโ€โ™‚๏ธ ๐Ÿง˜๐Ÿฟโ€โ™‚๏ธ ๐Ÿ„โ€โ™€๏ธ ๐Ÿ„๐Ÿปโ€โ™€๏ธ ๐Ÿ„๐Ÿผโ€โ™€๏ธ ๐Ÿ„๐Ÿฝโ€โ™€๏ธ ๐Ÿ„๐Ÿพโ€โ™€๏ธ ๐Ÿ„๐Ÿฟโ€โ™€๏ธ ๐Ÿ„โ€โ™‚๏ธ ๐Ÿ„๐Ÿปโ€โ™‚๏ธ ๐Ÿ„๐Ÿผโ€โ™‚๏ธ ๐Ÿ„๐Ÿฝโ€โ™‚๏ธ ๐Ÿ„๐Ÿพโ€โ™‚๏ธ ๐Ÿ„๐Ÿฟโ€โ™‚๏ธ ๐ŸŠโ€โ™€๏ธ ๐ŸŠ๐Ÿปโ€โ™€๏ธ ๐ŸŠ๐Ÿผโ€โ™€๏ธ ๐ŸŠ๐Ÿฝโ€โ™€๏ธ ๐ŸŠ๐Ÿพโ€โ™€๏ธ ๐ŸŠ๐Ÿฟโ€โ™€๏ธ ๐ŸŠโ€โ™‚๏ธ ๐ŸŠ๐Ÿปโ€โ™‚๏ธ ๐ŸŠ๐Ÿผโ€โ™‚๏ธ ๐ŸŠ๐Ÿฝโ€โ™‚๏ธ ๐ŸŠ๐Ÿพโ€โ™‚๏ธ ๐ŸŠ๐Ÿฟโ€โ™‚๏ธ ๐Ÿคฝโ€โ™€๏ธ ๐Ÿคฝ๐Ÿปโ€โ™€๏ธ ๐Ÿคฝ๐Ÿผโ€โ™€๏ธ ๐Ÿคฝ๐Ÿฝโ€โ™€๏ธ ๐Ÿคฝ๐Ÿพโ€โ™€๏ธ ๐Ÿคฝ๐Ÿฟโ€โ™€๏ธ ๐Ÿคฝโ€โ™‚๏ธ ๐Ÿคฝ๐Ÿปโ€โ™‚๏ธ ๐Ÿคฝ๐Ÿผโ€โ™‚๏ธ ๐Ÿคฝ๐Ÿฝโ€โ™‚๏ธ ๐Ÿคฝ๐Ÿพโ€โ™‚๏ธ ๐Ÿคฝ๐Ÿฟโ€โ™‚๏ธ ๐Ÿšฃโ€โ™€๏ธ ๐Ÿšฃ๐Ÿปโ€โ™€๏ธ ๐Ÿšฃ๐Ÿผโ€โ™€๏ธ ๐Ÿšฃ๐Ÿฝโ€โ™€๏ธ ๐Ÿšฃ๐Ÿพโ€โ™€๏ธ ๐Ÿšฃ๐Ÿฟโ€โ™€๏ธ ๐Ÿšฃโ€โ™‚๏ธ ๐Ÿšฃ๐Ÿปโ€โ™‚๏ธ ๐Ÿšฃ๐Ÿผโ€โ™‚๏ธ ๐Ÿšฃ๐Ÿฝโ€โ™‚๏ธ ๐Ÿšฃ๐Ÿพโ€โ™‚๏ธ ๐Ÿšฃ๐Ÿฟโ€โ™‚๏ธ ๐Ÿง—โ€โ™€๏ธ ๐Ÿง—๐Ÿปโ€โ™€๏ธ ๐Ÿง—๐Ÿผโ€โ™€๏ธ ๐Ÿง—๐Ÿฝโ€โ™€๏ธ ๐Ÿง—๐Ÿพโ€โ™€๏ธ ๐Ÿง—๐Ÿฟโ€โ™€๏ธ ๐Ÿง—โ€โ™‚๏ธ ๐Ÿง—๐Ÿปโ€โ™‚๏ธ ๐Ÿง—๐Ÿผโ€โ™‚๏ธ ๐Ÿง—๐Ÿฝโ€โ™‚๏ธ ๐Ÿง—๐Ÿพโ€โ™‚๏ธ ๐Ÿง—๐Ÿฟโ€โ™‚๏ธ ๐Ÿšตโ€โ™€๏ธ ๐Ÿšต๐Ÿปโ€โ™€๏ธ ๐Ÿšต๐Ÿผโ€โ™€๏ธ ๐Ÿšต๐Ÿฝโ€โ™€๏ธ ๐Ÿšต๐Ÿพโ€โ™€๏ธ ๐Ÿšต๐Ÿฟโ€โ™€๏ธ ๐Ÿšตโ€โ™‚๏ธ ๐Ÿšต๐Ÿปโ€โ™‚๏ธ ๐Ÿšต๐Ÿผโ€โ™‚๏ธ ๐Ÿšต๐Ÿฝโ€โ™‚๏ธ ๐Ÿšต๐Ÿพโ€โ™‚๏ธ ๐Ÿšต๐Ÿฟโ€โ™‚๏ธ ๐Ÿšดโ€โ™€๏ธ ๐Ÿšด๐Ÿปโ€โ™€๏ธ ๐Ÿšด๐Ÿผโ€โ™€๏ธ ๐Ÿšด๐Ÿฝโ€โ™€๏ธ ๐Ÿšด๐Ÿพโ€โ™€๏ธ ๐Ÿšด๐Ÿฟโ€โ™€๏ธ ๐Ÿšดโ€โ™‚๏ธ ๐Ÿšด๐Ÿปโ€โ™‚๏ธ ๐Ÿšด๐Ÿผโ€โ™‚๏ธ ๐Ÿšด๐Ÿฝโ€โ™‚๏ธ ๐Ÿšด๐Ÿพโ€โ™‚๏ธ ๐Ÿšด๐Ÿฟโ€โ™‚๏ธ ๐Ÿ† ๐Ÿฅ‡ ๐Ÿฅˆ ๐Ÿฅ‰ ๐Ÿ… ๐ŸŽ– ๐Ÿต ๐ŸŽ— ๐ŸŽซ ๐ŸŽŸ ๐ŸŽช ๐Ÿคนโ€โ™€๏ธ ๐Ÿคน๐Ÿปโ€โ™€๏ธ ๐Ÿคน๐Ÿผโ€โ™€๏ธ ๐Ÿคน๐Ÿฝโ€โ™€๏ธ ๐Ÿคน๐Ÿพโ€โ™€๏ธ ๐Ÿคน๐Ÿฟโ€โ™€๏ธ ๐Ÿคนโ€โ™‚๏ธ ๐Ÿคน๐Ÿปโ€โ™‚๏ธ ๐Ÿคน๐Ÿผโ€โ™‚๏ธ ๐Ÿคน๐Ÿฝโ€โ™‚๏ธ ๐Ÿคน๐Ÿพโ€โ™‚๏ธ ๐Ÿคน๐Ÿฟโ€โ™‚๏ธ ๐ŸŽญ ๐ŸŽจ ๐ŸŽฌ ๐ŸŽค ๐ŸŽง ๐ŸŽผ ๐ŸŽน ๐Ÿฅ ๐ŸŽท ๐ŸŽบ ๐ŸŽธ ๐ŸŽป ๐ŸŽฒ ๐Ÿงฉ โ™Ÿ ๐ŸŽฏ ๐ŸŽณ ๐ŸŽฎ ๐ŸŽฐ +๐Ÿš— ๐Ÿš• ๐Ÿš™ ๐ŸšŒ ๐ŸšŽ ๐ŸŽ ๐Ÿš“ ๐Ÿš‘ ๐Ÿš’ ๐Ÿš ๐Ÿšš ๐Ÿš› ๐Ÿšœ ๐Ÿ›ด ๐Ÿšฒ ๐Ÿ›ต ๐Ÿ ๐Ÿšจ ๐Ÿš” ๐Ÿš ๐Ÿš˜ ๐Ÿš– ๐Ÿšก ๐Ÿš  ๐ŸšŸ ๐Ÿšƒ ๐Ÿš‹ ๐Ÿšž ๐Ÿš ๐Ÿš„ ๐Ÿš… ๐Ÿšˆ ๐Ÿš‚ ๐Ÿš† ๐Ÿš‡ ๐ŸšŠ ๐Ÿš‰ โœˆ๏ธ ๐Ÿ›ซ ๐Ÿ›ฌ ๐Ÿ›ฉ ๐Ÿ’บ ๐Ÿ›ฐ ๐Ÿš€ ๐Ÿ›ธ ๐Ÿš ๐Ÿ›ถ โ›ต๏ธ ๐Ÿšค ๐Ÿ›ฅ ๐Ÿ›ณ โ›ด ๐Ÿšข โš“๏ธ โ›ฝ๏ธ ๐Ÿšง ๐Ÿšฆ ๐Ÿšฅ ๐Ÿš ๐Ÿ—บ ๐Ÿ—ฟ ๐Ÿ—ฝ ๐Ÿ—ผ ๐Ÿฐ ๐Ÿฏ ๐ŸŸ ๐ŸŽก ๐ŸŽข ๐ŸŽ  โ›ฒ๏ธ โ›ฑ ๐Ÿ– ๐Ÿ ๐Ÿœ ๐ŸŒ‹ โ›ฐ ๐Ÿ” ๐Ÿ—ป ๐Ÿ• โ›บ๏ธ ๐Ÿ  ๐Ÿก ๐Ÿ˜ ๐Ÿš ๐Ÿ— ๐Ÿญ ๐Ÿข ๐Ÿฌ ๐Ÿฃ ๐Ÿค ๐Ÿฅ ๐Ÿฆ ๐Ÿจ ๐Ÿช ๐Ÿซ ๐Ÿฉ ๐Ÿ’’ ๐Ÿ› โ›ช๏ธ ๐Ÿ•Œ ๐Ÿ• ๐Ÿ•‹ โ›ฉ ๐Ÿ›ค ๐Ÿ›ฃ ๐Ÿ—พ ๐ŸŽ‘ ๐Ÿž ๐ŸŒ… ๐ŸŒ„ ๐ŸŒ  ๐ŸŽ‡ ๐ŸŽ† ๐ŸŒ‡ ๐ŸŒ† ๐Ÿ™ ๐ŸŒƒ ๐ŸŒŒ ๐ŸŒ‰ ๐ŸŒ +โŒš๏ธ ๐Ÿ“ฑ ๐Ÿ“ฒ ๐Ÿ’ป โŒจ๏ธ ๐Ÿ–ฅ ๐Ÿ–จ ๐Ÿ–ฑ ๐Ÿ–ฒ ๐Ÿ•น ๐Ÿ—œ ๐Ÿ’ฝ ๐Ÿ’พ ๐Ÿ’ฟ ๐Ÿ“€ ๐Ÿ“ผ ๐Ÿ“ท ๐Ÿ“ธ ๐Ÿ“น ๐ŸŽฅ ๐Ÿ“ฝ ๐ŸŽž ๐Ÿ“ž โ˜Ž๏ธ ๐Ÿ“Ÿ ๐Ÿ“  ๐Ÿ“บ ๐Ÿ“ป ๐ŸŽ™ ๐ŸŽš ๐ŸŽ› โฑ โฒ โฐ ๐Ÿ•ฐ โŒ›๏ธ โณ ๐Ÿ“ก ๐Ÿ”‹ ๐Ÿ”Œ ๐Ÿ’ก ๐Ÿ”ฆ ๐Ÿ•ฏ ๐Ÿ—‘ ๐Ÿ›ข ๐Ÿ’ธ ๐Ÿ’ต ๐Ÿ’ด ๐Ÿ’ถ ๐Ÿ’ท ๐Ÿ’ฐ ๐Ÿ’ณ ๐Ÿงพ ๐Ÿ’Ž โš–๏ธ ๐Ÿ”ง ๐Ÿ”จ โš’ ๐Ÿ›  โ› ๐Ÿ”ฉ โš™๏ธ โ›“ ๐Ÿ”ซ ๐Ÿ’ฃ ๐Ÿ”ช ๐Ÿ—ก โš”๏ธ ๐Ÿ›ก ๐Ÿšฌ โšฐ๏ธ โšฑ๏ธ ๐Ÿบ ๐Ÿงญ ๐Ÿงฑ ๐Ÿ”ฎ ๐Ÿงฟ ๐Ÿงธ ๐Ÿ“ฟ ๐Ÿ’ˆ โš—๏ธ ๐Ÿ”ญ ๐Ÿงฐ ๐Ÿงฒ ๐Ÿงช ๐Ÿงซ ๐Ÿงฌ ๐Ÿงฏ ๐Ÿ”ฌ ๐Ÿ•ณ ๐Ÿ’Š ๐Ÿ’‰ ๐ŸŒก ๐Ÿšฝ ๐Ÿšฐ ๐Ÿšฟ ๐Ÿ› ๐Ÿ›€ ๐Ÿ›€๐Ÿป ๐Ÿ›€๐Ÿผ ๐Ÿ›€๐Ÿฝ ๐Ÿ›€๐Ÿพ ๐Ÿ›€๐Ÿฟ ๐Ÿงด ๐Ÿงต ๐Ÿงถ ๐Ÿงท ๐Ÿงน ๐Ÿงบ ๐Ÿงป ๐Ÿงผ ๐Ÿงฝ ๐Ÿ›Ž ๐Ÿ”‘ ๐Ÿ— ๐Ÿšช ๐Ÿ›‹ ๐Ÿ› ๐Ÿ›Œ ๐Ÿ–ผ ๐Ÿ› ๐Ÿงณ ๐Ÿ›’ ๐ŸŽ ๐ŸŽˆ ๐ŸŽ ๐ŸŽ€ ๐ŸŽŠ ๐ŸŽ‰ ๐Ÿงจ ๐ŸŽŽ ๐Ÿฎ ๐ŸŽ ๐Ÿงง โœ‰๏ธ ๐Ÿ“ฉ ๐Ÿ“จ ๐Ÿ“ง ๐Ÿ’Œ ๐Ÿ“ฅ ๐Ÿ“ค ๐Ÿ“ฆ ๐Ÿท ๐Ÿ“ช ๐Ÿ“ซ ๐Ÿ“ฌ ๐Ÿ“ญ ๐Ÿ“ฎ ๐Ÿ“ฏ ๐Ÿ“œ ๐Ÿ“ƒ ๐Ÿ“„ ๐Ÿ“‘ ๐Ÿ“Š ๐Ÿ“ˆ ๐Ÿ“‰ ๐Ÿ—’ ๐Ÿ—“ ๐Ÿ“† ๐Ÿ“… ๐Ÿ“‡ ๐Ÿ—ƒ ๐Ÿ—ณ ๐Ÿ—„ ๐Ÿ“‹ ๐Ÿ“ ๐Ÿ“‚ ๐Ÿ—‚ ๐Ÿ—ž ๐Ÿ“ฐ ๐Ÿ““ ๐Ÿ“” ๐Ÿ“’ ๐Ÿ“• ๐Ÿ“— ๐Ÿ“˜ ๐Ÿ“™ ๐Ÿ“š ๐Ÿ“– ๐Ÿ”– ๐Ÿ”— ๐Ÿ“Ž ๐Ÿ–‡ ๐Ÿ“ ๐Ÿ“ ๐Ÿ“Œ ๐Ÿ“ โœ‚๏ธ ๐Ÿ–Š ๐Ÿ–‹ โœ’๏ธ ๐Ÿ–Œ ๐Ÿ– ๐Ÿ“ โœ๏ธ ๐Ÿ” ๐Ÿ”Ž ๐Ÿ” ๐Ÿ” ๐Ÿ”’ ๐Ÿ”“ +โค๏ธ ๐Ÿงก ๐Ÿ’› ๐Ÿ’š ๐Ÿ’™ ๐Ÿ’œ ๐Ÿ–ค ๐Ÿ’” โฃ๏ธ ๐Ÿ’• ๐Ÿ’ž ๐Ÿ’“ ๐Ÿ’— ๐Ÿ’– ๐Ÿ’˜ ๐Ÿ’ ๐Ÿ’Ÿ โ˜ฎ๏ธ โœ๏ธ โ˜ช๏ธ ๐Ÿ•‰ โ˜ธ๏ธ โœก๏ธ ๐Ÿ”ฏ ๐Ÿ•Ž โ˜ฏ๏ธ โ˜ฆ๏ธ ๐Ÿ› โ›Ž โ™ˆ๏ธ โ™‰๏ธ โ™Š๏ธ โ™‹๏ธ โ™Œ๏ธ โ™๏ธ โ™Ž๏ธ โ™๏ธ โ™๏ธ โ™‘๏ธ โ™’๏ธ โ™“๏ธ ๐Ÿ†” โš›๏ธ ๐Ÿ‰‘ โ˜ข๏ธ โ˜ฃ๏ธ ๐Ÿ“ด ๐Ÿ“ณ ๐Ÿˆถ ๐Ÿˆš๏ธ ๐Ÿˆธ ๐Ÿˆบ ๐Ÿˆท๏ธ โœด๏ธ ๐Ÿ†š ๐Ÿ’ฎ ๐Ÿ‰ ใŠ™๏ธ ใŠ—๏ธ ๐Ÿˆด ๐Ÿˆต ๐Ÿˆน ๐Ÿˆฒ ๐Ÿ…ฐ๏ธ ๐Ÿ…ฑ๏ธ ๐Ÿ†Ž ๐Ÿ†‘ ๐Ÿ…พ๏ธ ๐Ÿ†˜ โŒ โญ•๏ธ ๐Ÿ›‘ โ›”๏ธ ๐Ÿ“› ๐Ÿšซ ๐Ÿ’ฏ ๐Ÿ’ข โ™จ๏ธ ๐Ÿšท ๐Ÿšฏ ๐Ÿšณ ๐Ÿšฑ ๐Ÿ”ž ๐Ÿ“ต ๐Ÿšญ โ—๏ธ โ• โ“ โ” โ€ผ๏ธ โ‰๏ธ ๐Ÿ”… ๐Ÿ”† ใ€ฝ๏ธ โš ๏ธ ๐Ÿšธ ๐Ÿ”ฑ โšœ๏ธ ๐Ÿ”ฐ โ™ป๏ธ โœ… ๐Ÿˆฏ๏ธ ๐Ÿ’น โ‡๏ธ โœณ๏ธ โŽ ๐ŸŒ ๐Ÿ’  โ“‚๏ธ ๐ŸŒ€ ๐Ÿ’ค ๐Ÿง ๐Ÿšพ โ™ฟ๏ธ ๐Ÿ…ฟ๏ธ ๐Ÿˆณ ๐Ÿˆ‚๏ธ ๐Ÿ›‚ ๐Ÿ›ƒ ๐Ÿ›„ ๐Ÿ›… ๐Ÿšน ๐Ÿšบ ๐Ÿšผ ๐Ÿšป ๐Ÿšฎ ๐ŸŽฆ ๐Ÿ“ถ ๐Ÿˆ ๐Ÿ”ฃ โ„น๏ธ ๐Ÿ”ค ๐Ÿ”ก ๐Ÿ”  ๐Ÿ†– ๐Ÿ†— ๐Ÿ†™ ๐Ÿ†’ ๐Ÿ†• ๐Ÿ†“ 0๏ธโƒฃ 1๏ธโƒฃ 2๏ธโƒฃ 3๏ธโƒฃ 4๏ธโƒฃ 5๏ธโƒฃ 6๏ธโƒฃ 7๏ธโƒฃ 8๏ธโƒฃ 9๏ธโƒฃ ๐Ÿ”Ÿ ๐Ÿ”ข #๏ธโƒฃ *๏ธโƒฃ โ๏ธ โ–ถ๏ธ โธ โฏ โน โบ โญ โฎ โฉ โช โซ โฌ โ—€๏ธ ๐Ÿ”ผ ๐Ÿ”ฝ โžก๏ธ โฌ…๏ธ โฌ†๏ธ โฌ‡๏ธ โ†—๏ธ โ†˜๏ธ โ†™๏ธ โ†–๏ธ โ†•๏ธ โ†”๏ธ โ†ช๏ธ โ†ฉ๏ธ โคด๏ธ โคต๏ธ ๐Ÿ”€ ๐Ÿ” ๐Ÿ”‚ ๐Ÿ”„ ๐Ÿ”ƒ ๐ŸŽต ๐ŸŽถ โž• โž– โž— โœ–๏ธ โ™พ ๐Ÿ’ฒ ๐Ÿ’ฑ โ„ข๏ธ ยฉ๏ธ ยฎ๏ธ ใ€ฐ๏ธ โžฐ โžฟ ๐Ÿ”š ๐Ÿ”™ ๐Ÿ”› ๐Ÿ” ๐Ÿ”œ โœ”๏ธ โ˜‘๏ธ ๐Ÿ”˜ โšช๏ธ โšซ๏ธ ๐Ÿ”ด ๐Ÿ”ต ๐Ÿ”บ ๐Ÿ”ป ๐Ÿ”ธ ๐Ÿ”น ๐Ÿ”ถ ๐Ÿ”ท ๐Ÿ”ณ ๐Ÿ”ฒ โ–ช๏ธ โ–ซ๏ธ โ—พ๏ธ โ—ฝ๏ธ โ—ผ๏ธ โ—ป๏ธ โฌ›๏ธ โฌœ๏ธ ๐Ÿ”ˆ ๐Ÿ”‡ ๐Ÿ”‰ ๐Ÿ”Š ๐Ÿ”” ๐Ÿ”• ๐Ÿ“ฃ ๐Ÿ“ข ๐Ÿ‘โ€๐Ÿ—จ ๐Ÿ’ฌ ๐Ÿ’ญ ๐Ÿ—ฏ โ™ ๏ธ โ™ฃ๏ธ โ™ฅ๏ธ โ™ฆ๏ธ ๐Ÿƒ ๐ŸŽด ๐Ÿ€„๏ธ ๐Ÿ• ๐Ÿ•‘ ๐Ÿ•’ ๐Ÿ•“ ๐Ÿ•” ๐Ÿ•• ๐Ÿ•– ๐Ÿ•— ๐Ÿ•˜ ๐Ÿ•™ ๐Ÿ•š ๐Ÿ•› ๐Ÿ•œ ๐Ÿ• ๐Ÿ•ž ๐Ÿ•Ÿ ๐Ÿ•  ๐Ÿ•ก ๐Ÿ•ข ๐Ÿ•ฃ ๐Ÿ•ค ๐Ÿ•ฅ ๐Ÿ•ฆ ๐Ÿ•ง +๐Ÿณ๏ธ ๐Ÿด ๐Ÿ ๐Ÿšฉ ๐Ÿณ๏ธโ€๐ŸŒˆ ๐Ÿดโ€โ˜ ๏ธ ๐Ÿ‡ฆ๐Ÿ‡ซ ๐Ÿ‡ฆ๐Ÿ‡ฝ ๐Ÿ‡ฆ๐Ÿ‡ฑ ๐Ÿ‡ฉ๐Ÿ‡ฟ ๐Ÿ‡ฆ๐Ÿ‡ธ ๐Ÿ‡ฆ๐Ÿ‡ฉ ๐Ÿ‡ฆ๐Ÿ‡ด ๐Ÿ‡ฆ๐Ÿ‡ฎ ๐Ÿ‡ฆ๐Ÿ‡ถ ๐Ÿ‡ฆ๐Ÿ‡ฌ ๐Ÿ‡ฆ๐Ÿ‡ท ๐Ÿ‡ฆ๐Ÿ‡ฒ ๐Ÿ‡ฆ๐Ÿ‡ผ ๐Ÿ‡ฆ๐Ÿ‡บ ๐Ÿ‡ฆ๐Ÿ‡น ๐Ÿ‡ฆ๐Ÿ‡ฟ ๐Ÿ‡ง๐Ÿ‡ธ ๐Ÿ‡ง๐Ÿ‡ญ ๐Ÿ‡ง๐Ÿ‡ฉ ๐Ÿ‡ง๐Ÿ‡ง ๐Ÿ‡ง๐Ÿ‡พ ๐Ÿ‡ง๐Ÿ‡ช ๐Ÿ‡ง๐Ÿ‡ฟ ๐Ÿ‡ง๐Ÿ‡ฏ ๐Ÿ‡ง๐Ÿ‡ฒ ๐Ÿ‡ง๐Ÿ‡น ๐Ÿ‡ง๐Ÿ‡ด ๐Ÿ‡ง๐Ÿ‡ฆ ๐Ÿ‡ง๐Ÿ‡ผ ๐Ÿ‡ง๐Ÿ‡ท ๐Ÿ‡ฎ๐Ÿ‡ด ๐Ÿ‡ป๐Ÿ‡ฌ ๐Ÿ‡ง๐Ÿ‡ณ ๐Ÿ‡ง๐Ÿ‡ฌ ๐Ÿ‡ง๐Ÿ‡ซ ๐Ÿ‡ง๐Ÿ‡ฎ ๐Ÿ‡ฐ๐Ÿ‡ญ ๐Ÿ‡จ๐Ÿ‡ฒ ๐Ÿ‡จ๐Ÿ‡ฆ ๐Ÿ‡ฎ๐Ÿ‡จ ๐Ÿ‡จ๐Ÿ‡ป ๐Ÿ‡ง๐Ÿ‡ถ ๐Ÿ‡ฐ๐Ÿ‡พ ๐Ÿ‡จ๐Ÿ‡ซ ๐Ÿ‡น๐Ÿ‡ฉ ๐Ÿ‡จ๐Ÿ‡ฑ ๐Ÿ‡จ๐Ÿ‡ณ ๐Ÿ‡จ๐Ÿ‡ฝ ๐Ÿ‡จ๐Ÿ‡จ ๐Ÿ‡จ๐Ÿ‡ด ๐Ÿ‡ฐ๐Ÿ‡ฒ ๐Ÿ‡จ๐Ÿ‡ฌ ๐Ÿ‡จ๐Ÿ‡ฉ ๐Ÿ‡จ๐Ÿ‡ฐ ๐Ÿ‡จ๐Ÿ‡ท ๐Ÿ‡จ๐Ÿ‡ฎ ๐Ÿ‡ญ๐Ÿ‡ท ๐Ÿ‡จ๐Ÿ‡บ ๐Ÿ‡จ๐Ÿ‡ผ ๐Ÿ‡จ๐Ÿ‡พ ๐Ÿ‡จ๐Ÿ‡ฟ ๐Ÿ‡ฉ๐Ÿ‡ฐ ๐Ÿ‡ฉ๐Ÿ‡ฏ ๐Ÿ‡ฉ๐Ÿ‡ฒ ๐Ÿ‡ฉ๐Ÿ‡ด ๐Ÿ‡ช๐Ÿ‡จ ๐Ÿ‡ช๐Ÿ‡ฌ ๐Ÿ‡ธ๐Ÿ‡ป ๐Ÿ‡ฌ๐Ÿ‡ถ ๐Ÿ‡ช๐Ÿ‡ท ๐Ÿ‡ช๐Ÿ‡ช ๐Ÿ‡ช๐Ÿ‡น ๐Ÿ‡ช๐Ÿ‡บ ๐Ÿ‡ซ๐Ÿ‡ฐ ๐Ÿ‡ซ๐Ÿ‡ด ๐Ÿ‡ซ๐Ÿ‡ฏ ๐Ÿ‡ซ๐Ÿ‡ฎ ๐Ÿ‡ซ๐Ÿ‡ท ๐Ÿ‡ฌ๐Ÿ‡ซ ๐Ÿ‡ต๐Ÿ‡ซ ๐Ÿ‡น๐Ÿ‡ซ ๐Ÿ‡ฌ๐Ÿ‡ฆ ๐Ÿ‡ฌ๐Ÿ‡ฒ ๐Ÿ‡ฌ๐Ÿ‡ช ๐Ÿ‡ฉ๐Ÿ‡ช ๐Ÿ‡ฌ๐Ÿ‡ญ ๐Ÿ‡ฌ๐Ÿ‡ฎ ๐Ÿ‡ฌ๐Ÿ‡ท ๐Ÿ‡ฌ๐Ÿ‡ฑ ๐Ÿ‡ฌ๐Ÿ‡ฉ ๐Ÿ‡ฌ๐Ÿ‡ต ๐Ÿ‡ฌ๐Ÿ‡บ ๐Ÿ‡ฌ๐Ÿ‡น ๐Ÿ‡ฌ๐Ÿ‡ฌ ๐Ÿ‡ฌ๐Ÿ‡ณ ๐Ÿ‡ฌ๐Ÿ‡ผ ๐Ÿ‡ฌ๐Ÿ‡พ ๐Ÿ‡ญ๐Ÿ‡น ๐Ÿ‡ญ๐Ÿ‡ณ ๐Ÿ‡ญ๐Ÿ‡ฐ ๐Ÿ‡ญ๐Ÿ‡บ ๐Ÿ‡ฎ๐Ÿ‡ธ ๐Ÿ‡ฎ๐Ÿ‡ณ ๐Ÿ‡ฎ๐Ÿ‡ฉ ๐Ÿ‡ฎ๐Ÿ‡ท ๐Ÿ‡ฎ๐Ÿ‡ถ ๐Ÿ‡ฎ๐Ÿ‡ช ๐Ÿ‡ฎ๐Ÿ‡ฒ ๐Ÿ‡ฎ๐Ÿ‡ฑ ๐Ÿ‡ฎ๐Ÿ‡น ๐Ÿ‡ฏ๐Ÿ‡ฒ ๐Ÿ‡ฏ๐Ÿ‡ต ๐ŸŽŒ ๐Ÿ‡ฏ๐Ÿ‡ช ๐Ÿ‡ฏ๐Ÿ‡ด ๐Ÿ‡ฐ๐Ÿ‡ฟ ๐Ÿ‡ฐ๐Ÿ‡ช ๐Ÿ‡ฐ๐Ÿ‡ฎ ๐Ÿ‡ฝ๐Ÿ‡ฐ ๐Ÿ‡ฐ๐Ÿ‡ผ ๐Ÿ‡ฐ๐Ÿ‡ฌ ๐Ÿ‡ฑ๐Ÿ‡ฆ ๐Ÿ‡ฑ๐Ÿ‡ป ๐Ÿ‡ฑ๐Ÿ‡ง ๐Ÿ‡ฑ๐Ÿ‡ธ ๐Ÿ‡ฑ๐Ÿ‡ท ๐Ÿ‡ฑ๐Ÿ‡พ ๐Ÿ‡ฑ๐Ÿ‡ฎ ๐Ÿ‡ฑ๐Ÿ‡น ๐Ÿ‡ฑ๐Ÿ‡บ ๐Ÿ‡ฒ๐Ÿ‡ด ๐Ÿ‡ฒ๐Ÿ‡ฐ ๐Ÿ‡ฒ๐Ÿ‡ฌ ๐Ÿ‡ฒ๐Ÿ‡ผ ๐Ÿ‡ฒ๐Ÿ‡พ ๐Ÿ‡ฒ๐Ÿ‡ป ๐Ÿ‡ฒ๐Ÿ‡ฑ ๐Ÿ‡ฒ๐Ÿ‡น ๐Ÿ‡ฒ๐Ÿ‡ญ ๐Ÿ‡ฒ๐Ÿ‡ถ ๐Ÿ‡ฒ๐Ÿ‡ท ๐Ÿ‡ฒ๐Ÿ‡บ ๐Ÿ‡พ๐Ÿ‡น ๐Ÿ‡ฒ๐Ÿ‡ฝ ๐Ÿ‡ซ๐Ÿ‡ฒ ๐Ÿ‡ฒ๐Ÿ‡ฉ ๐Ÿ‡ฒ๐Ÿ‡จ ๐Ÿ‡ฒ๐Ÿ‡ณ ๐Ÿ‡ฒ๐Ÿ‡ช ๐Ÿ‡ฒ๐Ÿ‡ธ ๐Ÿ‡ฒ๐Ÿ‡ฆ ๐Ÿ‡ฒ๐Ÿ‡ฟ ๐Ÿ‡ฒ๐Ÿ‡ฒ ๐Ÿ‡ณ๐Ÿ‡ฆ ๐Ÿ‡ณ๐Ÿ‡ท ๐Ÿ‡ณ๐Ÿ‡ต ๐Ÿ‡ณ๐Ÿ‡ฑ ๐Ÿ‡ณ๐Ÿ‡จ ๐Ÿ‡ณ๐Ÿ‡ฟ ๐Ÿ‡ณ๐Ÿ‡ฎ ๐Ÿ‡ณ๐Ÿ‡ช ๐Ÿ‡ณ๐Ÿ‡ฌ ๐Ÿ‡ณ๐Ÿ‡บ ๐Ÿ‡ณ๐Ÿ‡ซ ๐Ÿ‡ฐ๐Ÿ‡ต ๐Ÿ‡ฒ๐Ÿ‡ต ๐Ÿ‡ณ๐Ÿ‡ด ๐Ÿ‡ด๐Ÿ‡ฒ ๐Ÿ‡ต๐Ÿ‡ฐ ๐Ÿ‡ต๐Ÿ‡ผ ๐Ÿ‡ต๐Ÿ‡ธ ๐Ÿ‡ต๐Ÿ‡ฆ ๐Ÿ‡ต๐Ÿ‡ฌ ๐Ÿ‡ต๐Ÿ‡พ ๐Ÿ‡ต๐Ÿ‡ช ๐Ÿ‡ต๐Ÿ‡ญ ๐Ÿ‡ต๐Ÿ‡ณ ๐Ÿ‡ต๐Ÿ‡ฑ ๐Ÿ‡ต๐Ÿ‡น ๐Ÿ‡ต๐Ÿ‡ท ๐Ÿ‡ถ๐Ÿ‡ฆ ๐Ÿ‡ท๐Ÿ‡ช ๐Ÿ‡ท๐Ÿ‡ด ๐Ÿ‡ท๐Ÿ‡บ ๐Ÿ‡ท๐Ÿ‡ผ ๐Ÿ‡ผ๐Ÿ‡ธ ๐Ÿ‡ธ๐Ÿ‡ฒ ๐Ÿ‡ธ๐Ÿ‡ฆ ๐Ÿ‡ธ๐Ÿ‡ณ ๐Ÿ‡ท๐Ÿ‡ธ ๐Ÿ‡ธ๐Ÿ‡จ ๐Ÿ‡ธ๐Ÿ‡ฑ ๐Ÿ‡ธ๐Ÿ‡ฌ ๐Ÿ‡ธ๐Ÿ‡ฝ ๐Ÿ‡ธ๐Ÿ‡ฐ ๐Ÿ‡ธ๐Ÿ‡ฎ ๐Ÿ‡ฌ๐Ÿ‡ธ ๐Ÿ‡ธ๐Ÿ‡ง ๐Ÿ‡ธ๐Ÿ‡ด ๐Ÿ‡ฟ๐Ÿ‡ฆ ๐Ÿ‡ฐ๐Ÿ‡ท ๐Ÿ‡ธ๐Ÿ‡ธ ๐Ÿ‡ช๐Ÿ‡ธ ๐Ÿ‡ฑ๐Ÿ‡ฐ ๐Ÿ‡ง๐Ÿ‡ฑ ๐Ÿ‡ธ๐Ÿ‡ญ ๐Ÿ‡ฐ๐Ÿ‡ณ ๐Ÿ‡ฑ๐Ÿ‡จ ๐Ÿ‡ต๐Ÿ‡ฒ ๐Ÿ‡ป๐Ÿ‡จ ๐Ÿ‡ธ๐Ÿ‡ฉ ๐Ÿ‡ธ๐Ÿ‡ท ๐Ÿ‡ธ๐Ÿ‡ฟ ๐Ÿ‡ธ๐Ÿ‡ช ๐Ÿ‡จ๐Ÿ‡ญ ๐Ÿ‡ธ๐Ÿ‡พ ๐Ÿ‡น๐Ÿ‡ผ ๐Ÿ‡น๐Ÿ‡ฏ ๐Ÿ‡น๐Ÿ‡ฟ ๐Ÿ‡น๐Ÿ‡ญ ๐Ÿ‡น๐Ÿ‡ฑ ๐Ÿ‡น๐Ÿ‡ฌ ๐Ÿ‡น๐Ÿ‡ฐ ๐Ÿ‡น๐Ÿ‡ด ๐Ÿ‡น๐Ÿ‡น ๐Ÿ‡น๐Ÿ‡ณ ๐Ÿ‡น๐Ÿ‡ท ๐Ÿ‡น๐Ÿ‡ฒ ๐Ÿ‡น๐Ÿ‡จ ๐Ÿ‡น๐Ÿ‡ป ๐Ÿ‡ป๐Ÿ‡ฎ ๐Ÿ‡บ๐Ÿ‡ฌ ๐Ÿ‡บ๐Ÿ‡ฆ ๐Ÿ‡ฆ๐Ÿ‡ช ๐Ÿ‡ฌ๐Ÿ‡ง ๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ ๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ ๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ ๐Ÿ‡บ๐Ÿ‡ณ ๐Ÿ‡บ๐Ÿ‡ธ ๐Ÿ‡บ๐Ÿ‡พ ๐Ÿ‡บ๐Ÿ‡ฟ ๐Ÿ‡ป๐Ÿ‡บ ๐Ÿ‡ป๐Ÿ‡ฆ ๐Ÿ‡ป๐Ÿ‡ช ๐Ÿ‡ป๐Ÿ‡ณ ๐Ÿ‡ผ๐Ÿ‡ซ ๐Ÿ‡ช๐Ÿ‡ญ ๐Ÿ‡พ๐Ÿ‡ช ๐Ÿ‡ฟ๐Ÿ‡ฒ ๐Ÿ‡ฟ๐Ÿ‡ผ +๐Ÿฅฑ ๐Ÿค ๐Ÿฆพ ๐Ÿฆฟ ๐Ÿฆป ๐Ÿง ๐Ÿงโ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐Ÿง ๐Ÿงโ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐ŸงŽ ๐ŸงŽโ€โ™‚๏ธ ๐ŸงŽโ€โ™€๏ธ ๐Ÿ‘จโ€๐Ÿฆฏ ๐Ÿ‘ฉโ€๐Ÿฆฏ ๐Ÿ‘จโ€๐Ÿฆผ ๐Ÿ‘ฉโ€๐Ÿฆผ ๐Ÿ‘จโ€๐Ÿฆฝ ๐Ÿ‘ฉโ€๐Ÿฆฝ ๐Ÿฆง ๐Ÿฆฎ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿฆฅ ๐Ÿฆฆ ๐Ÿฆจ ๐Ÿฆฉ ๐Ÿง„ ๐Ÿง… ๐Ÿง‡ ๐Ÿง† ๐Ÿงˆ ๐Ÿฆช ๐Ÿงƒ ๐Ÿง‰ ๐ŸงŠ ๐Ÿ›• ๐Ÿฆฝ ๐Ÿฆผ ๐Ÿ›บ ๐Ÿช‚ ๐Ÿช ๐Ÿคฟ ๐Ÿช€ ๐Ÿช ๐Ÿฆบ ๐Ÿฅป ๐Ÿฉฑ ๐Ÿฉฒ ๐Ÿฉณ ๐Ÿฉฐ ๐Ÿช• ๐Ÿช” ๐Ÿช“ ๐Ÿฆฏ ๐Ÿฉธ ๐Ÿฉน ๐Ÿฉบ ๐Ÿช‘ ๐Ÿช’ ๐ŸคŽ ๐Ÿค ๐ŸŸ  ๐ŸŸก ๐ŸŸข ๐ŸŸฃ ๐ŸŸค ๐ŸŸฅ ๐ŸŸง ๐ŸŸจ ๐ŸŸฉ ๐ŸŸฆ ๐ŸŸช ๐ŸŸซ"; + + [Benchmark] + public TextLayout BuildEmojisTextLayout() => new TextLayout(Emojis, Typeface.Default, 12d, Brushes.Black); + + public void Dispose() + { + _app?.Dispose(); + } +} diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs index 2790bd6096..7501bf21fe 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs @@ -153,7 +153,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting { while (inner.MoveNext()) { - j += inner.Current.Text.Length; + j += inner.Current.Length; if (j + i > text.Length) { @@ -192,7 +192,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting inner = new GraphemeEnumerator(new CharacterBufferRange(text)); - i += outer.Current.Text.Length; + i += outer.Current.Length; } } } @@ -974,9 +974,9 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting { var grapheme = graphemeEnumerator.Current; - var textStyleOverrides = new[] { new ValueSpan(i, grapheme.Text.Length, new GenericTextRunProperties(Typeface.Default, 12, foregroundBrush: Brushes.Red)) }; + var textStyleOverrides = new[] { new ValueSpan(i, grapheme.Length, new GenericTextRunProperties(Typeface.Default, 12, foregroundBrush: Brushes.Red)) }; - i += grapheme.Text.Length; + i += grapheme.Length; var layout = new TextLayout( text, From 8c30948e62dcf565d26dbda39020c5dbb15f096a Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 04:59:46 +0300 Subject: [PATCH 26/30] [Text] optimize CharacterBufferReference indexator --- src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs index d76f212f26..86e44a5269 100644 --- a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs +++ b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs @@ -140,7 +140,7 @@ namespace Avalonia.Media.TextFormatting throw new ArgumentOutOfRangeException(nameof(index)); } #endif - return Span[index]; + return CharacterBufferReference.CharacterBuffer.Span[CharacterBufferReference.OffsetToFirstChar + index]; } } From 5bd28141b78d88bb72eb92fe4edb00451dc1e7d8 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 05:07:27 +0300 Subject: [PATCH 27/30] [Text] minor optimize of CharacterBufferRange --- .../TextFormatting/CharacterBufferRange.cs | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs index 86e44a5269..599b35dd2c 100644 --- a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs +++ b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs @@ -147,12 +147,12 @@ namespace Avalonia.Media.TextFormatting /// /// Gets a reference to the character buffer /// - public CharacterBufferReference CharacterBufferReference { get; } + public readonly CharacterBufferReference CharacterBufferReference; /// /// Gets the number of characters in text source character store /// - public int Length { get; } + public readonly int Length; /// /// Gets a span from the character buffer range @@ -163,27 +163,18 @@ namespace Avalonia.Media.TextFormatting /// /// Gets the character memory buffer /// - internal ReadOnlyMemory CharacterBuffer - { - get { return CharacterBufferReference.CharacterBuffer; } - } + internal ReadOnlyMemory CharacterBuffer => CharacterBufferReference.CharacterBuffer; /// /// Gets the character offset relative to the beginning of buffer to /// the first character of the run /// - internal int OffsetToFirstChar - { - get { return CharacterBufferReference.OffsetToFirstChar; } - } + internal int OffsetToFirstChar => CharacterBufferReference.OffsetToFirstChar; /// /// Indicate whether the character buffer range is empty /// - internal bool IsEmpty - { - get { return CharacterBufferReference.CharacterBuffer.Length == 0 || Length <= 0; } - } + internal bool IsEmpty => CharacterBufferReference.CharacterBuffer.Length == 0 || Length <= 0; internal CharacterBufferRange Take(int length) { @@ -280,14 +271,8 @@ namespace Avalonia.Media.TextFormatting int IReadOnlyCollection.Count => Length; - public IEnumerator GetEnumerator() - { - return new ImmutableReadOnlyListStructEnumerator(this); - } + public IEnumerator GetEnumerator() => new ImmutableReadOnlyListStructEnumerator(this); - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } From ba9bf5d3641df0d75c780c4ef021b7762764f3d6 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 05:13:50 +0300 Subject: [PATCH 28/30] [Text] Clone CodePoint ReadAt for Span --- .../Media/TextFormatting/Unicode/Codepoint.cs | 68 ++++++++++++++++++- .../Unicode/CodepointEnumerator.cs | 2 +- .../Unicode/GraphemeEnumerator.cs | 2 +- .../Avalonia.UnitTests/MockTextShaperImpl.cs | 2 +- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs index e6408bcfa6..ecd0681e15 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.Collections.Generic; +๏ปฟusing System; +using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Avalonia.Media.TextFormatting.Unicode @@ -222,6 +223,71 @@ namespace Avalonia.Media.TextFormatting.Unicode return new Codepoint(code); } + + /// + /// Reads the at specified position. + /// + /// The buffer to read from. + /// The index to read at. + /// The count of character that were read. + /// + public static Codepoint ReadAt(ReadOnlySpan text, int index, out int count) + { + count = 1; + + if (index >= text.Length) + { + return ReplacementCodepoint; + } + + var code = text[index]; + + ushort hi, low; + + //# High surrogate + if (0xD800 <= code && code <= 0xDBFF) + { + hi = code; + + if (index + 1 == text.Length) + { + return ReplacementCodepoint; + } + + low = text[index + 1]; + + if (0xDC00 <= low && low <= 0xDFFF) + { + count = 2; + return new Codepoint((uint)((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)); + } + + return ReplacementCodepoint; + } + + //# Low surrogate + if (0xDC00 <= code && code <= 0xDFFF) + { + if (index == 0) + { + return ReplacementCodepoint; + } + + hi = text[index - 1]; + + low = code; + + if (0xD800 <= hi && hi <= 0xDBFF) + { + count = 2; + return new Codepoint((uint)((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)); + } + + return ReplacementCodepoint; + } + + return new Codepoint(code); + } /// /// Returns if is between diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs index a2c36d9a13..a2e29812d3 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs @@ -30,7 +30,7 @@ namespace Avalonia.Media.TextFormatting.Unicode return false; } - Current = Codepoint.ReadAt(_text, 0, out var count); + Current = Codepoint.ReadAt(_text.Span, 0, out var count); _text = _text.Skip(count); diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs index dc21e06813..2488b620e7 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs @@ -245,7 +245,7 @@ namespace Avalonia.Media.TextFormatting.Unicode if (CurrentCodeUnitOffset < _buffer.Length) { - CurrentCodepoint = Codepoint.ReadAt(_buffer, CurrentCodeUnitOffset, + CurrentCodepoint = Codepoint.ReadAt(_buffer.Span, CurrentCodeUnitOffset, out _codeUnitLengthOfCurrentScalar); } else diff --git a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs index 00bcef295a..d010f9ebf2 100644 --- a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs +++ b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs @@ -18,7 +18,7 @@ namespace Avalonia.UnitTests { var glyphCluster = i + text.OffsetToFirstChar; - var codepoint = Codepoint.ReadAt(characterBufferRange, i, out var count); + var codepoint = Codepoint.ReadAt(characterBufferRange.Span, i, out var count); var glyphIndex = typeface.GetGlyph(codepoint); From 80972e5f5b287809caeabe0b8873c845061f7c34 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 05:23:58 +0300 Subject: [PATCH 29/30] [Text] a bit better usage of Codepoint.ReadAt --- src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs | 2 +- .../Media/TextFormatting/Unicode/CodepointEnumerator.cs | 2 +- .../Media/TextFormatting/Unicode/GraphemeEnumerator.cs | 2 +- tests/Avalonia.UnitTests/MockTextShaperImpl.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs index ecd0681e15..8b9d1c1d02 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs @@ -231,7 +231,7 @@ namespace Avalonia.Media.TextFormatting.Unicode /// The index to read at. /// The count of character that were read. /// - public static Codepoint ReadAt(ReadOnlySpan text, int index, out int count) + public static Codepoint ReadAt(CharacterBufferRange text, int index, out int count) { count = 1; diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs index a2e29812d3..a2c36d9a13 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/CodepointEnumerator.cs @@ -30,7 +30,7 @@ namespace Avalonia.Media.TextFormatting.Unicode return false; } - Current = Codepoint.ReadAt(_text.Span, 0, out var count); + Current = Codepoint.ReadAt(_text, 0, out var count); _text = _text.Skip(count); diff --git a/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs b/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs index 2488b620e7..dc21e06813 100644 --- a/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs +++ b/src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeEnumerator.cs @@ -245,7 +245,7 @@ namespace Avalonia.Media.TextFormatting.Unicode if (CurrentCodeUnitOffset < _buffer.Length) { - CurrentCodepoint = Codepoint.ReadAt(_buffer.Span, CurrentCodeUnitOffset, + CurrentCodepoint = Codepoint.ReadAt(_buffer, CurrentCodeUnitOffset, out _codeUnitLengthOfCurrentScalar); } else diff --git a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs index d010f9ebf2..00bcef295a 100644 --- a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs +++ b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs @@ -18,7 +18,7 @@ namespace Avalonia.UnitTests { var glyphCluster = i + text.OffsetToFirstChar; - var codepoint = Codepoint.ReadAt(characterBufferRange.Span, i, out var count); + var codepoint = Codepoint.ReadAt(characterBufferRange, i, out var count); var glyphIndex = typeface.GetGlyph(codepoint); From c9bf6310a8582afc10a504ae1b938267884a58f0 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 14:18:25 +0300 Subject: [PATCH 30/30] [Text] revert fields to props in CharacterBufferRange --- .../Media/TextFormatting/CharacterBufferRange.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs index 599b35dd2c..f5d39e4371 100644 --- a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs +++ b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs @@ -147,12 +147,12 @@ namespace Avalonia.Media.TextFormatting /// /// Gets a reference to the character buffer /// - public readonly CharacterBufferReference CharacterBufferReference; + public CharacterBufferReference CharacterBufferReference { get; } /// /// Gets the number of characters in text source character store /// - public readonly int Length; + public int Length { get; } /// /// Gets a span from the character buffer range