From ba9bf5d3641df0d75c780c4ef021b7762764f3d6 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaitis Date: Sat, 7 Jan 2023 05:13:50 +0300 Subject: [PATCH] [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);