diff --git a/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs b/src/Avalonia.Base/Media/TextFormatting/CharacterBufferRange.cs index f5d39e4371..499026e8b3 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 CharacterBufferReference.CharacterBuffer.Span[CharacterBufferReference.OffsetToFirstChar + index]; + return CharacterBuffer.Span[CharacterBufferReference.OffsetToFirstChar + index]; } } @@ -157,8 +157,7 @@ namespace Avalonia.Media.TextFormatting /// /// Gets a span from the character buffer range /// - public ReadOnlySpan Span => - CharacterBufferReference.CharacterBuffer.Span.Slice(CharacterBufferReference.OffsetToFirstChar, Length); + public ReadOnlySpan Span => CharacterBuffer.Span.Slice(OffsetToFirstChar, Length); /// /// Gets the character memory buffer @@ -174,7 +173,7 @@ namespace Avalonia.Media.TextFormatting /// /// Indicate whether the character buffer range is empty /// - internal bool IsEmpty => CharacterBufferReference.CharacterBuffer.Length == 0 || Length <= 0; + internal bool IsEmpty => CharacterBuffer.Length == 0 || Length <= 0; internal CharacterBufferRange Take(int length) { @@ -208,9 +207,7 @@ namespace Avalonia.Media.TextFormatting return new CharacterBufferRange(new CharacterBufferReference(), 0); } - var characterBufferReference = new CharacterBufferReference( - CharacterBufferReference.CharacterBuffer, - CharacterBufferReference.OffsetToFirstChar + length); + var characterBufferReference = new CharacterBufferReference(CharacterBuffer, OffsetToFirstChar + length); return new CharacterBufferRange(characterBufferReference, Length - length); } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs index 544800ecea..989bf7749d 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs @@ -130,7 +130,7 @@ namespace Avalonia.Media.TextFormatting first.Add(split.First); second.Add(split.Second!); - } + } for (var j = 1; j < secondCount; j++) { @@ -237,7 +237,7 @@ namespace Avalonia.Media.TextFormatting var shaperOptions = new TextShaperOptions(currentRun.Properties!.Typeface.GlyphTypeface, currentRun.Properties.FontRenderingEmSize, - shapeableRun.BidiLevel, currentRun.Properties.CultureInfo, + shapeableRun.BidiLevel, currentRun.Properties.CultureInfo, paragraphProperties.DefaultIncrementalTab, paragraphProperties.LetterSpacing); shapedRuns.AddRange(ShapeTogether(groupedRuns, characterBufferReference, length, shaperOptions)); @@ -478,7 +478,7 @@ namespace Avalonia.Media.TextFormatting { case ShapedTextRun shapedTextCharacters: { - if(shapedTextCharacters.ShapedBuffer.Length > 0) + if (shapedTextCharacters.ShapedBuffer.Length > 0) { var firstCluster = shapedTextCharacters.ShapedBuffer.GlyphInfos[0].GlyphCluster; var lastCluster = firstCluster; @@ -499,7 +499,7 @@ namespace Avalonia.Media.TextFormatting } measuredLength += currentRun.Length; - } + } break; } @@ -525,7 +525,7 @@ namespace Avalonia.Media.TextFormatting } } - found: + found: return measuredLength != 0; } @@ -565,9 +565,9 @@ namespace Avalonia.Media.TextFormatting double paragraphWidth, TextParagraphProperties paragraphProperties, FlowDirection resolvedFlowDirection, TextLineBreak? currentLineBreak) { - if(textRuns.Count == 0) + if (textRuns.Count == 0) { - return CreateEmptyTextLine(firstTextSourceIndex,paragraphWidth, paragraphProperties); + return CreateEmptyTextLine(firstTextSourceIndex, paragraphWidth, paragraphProperties); } if (!TryMeasureLength(textRuns, paragraphWidth, out var measuredLength)) @@ -583,46 +583,24 @@ namespace Avalonia.Media.TextFormatting for (var index = 0; index < textRuns.Count; index++) { - var currentRun = textRuns[index]; - - var runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length); - - var lineBreaker = new LineBreakEnumerator(runText); - var breakFound = false; - while (lineBreaker.MoveNext()) - { - if (lineBreaker.Current.Required && - currentLength + lineBreaker.Current.PositionMeasure <= measuredLength) - { - //Explicit break found - breakFound = true; - - currentPosition = currentLength + lineBreaker.Current.PositionWrap; - - break; - } + var currentRun = textRuns[index]; - if (currentLength + lineBreaker.Current.PositionMeasure > measuredLength) - { - if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow) + switch (currentRun) + { + case ShapedTextRun: { - if (lastWrapPosition > 0) - { - currentPosition = lastWrapPosition; + var runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length); - breakFound = true; + var lineBreaker = new LineBreakEnumerator(runText); - break; - } - - //Find next possible wrap position (overflow) - if (index < textRuns.Count - 1) + while (lineBreaker.MoveNext()) { - if (lineBreaker.Current.PositionWrap != currentRun.Length) + if (lineBreaker.Current.Required && + currentLength + lineBreaker.Current.PositionMeasure <= measuredLength) { - //We already found the next possible wrap position. + //Explicit break found breakFound = true; currentPosition = currentLength + lineBreaker.Current.PositionWrap; @@ -630,51 +608,81 @@ namespace Avalonia.Media.TextFormatting break; } - while (lineBreaker.MoveNext() && index < textRuns.Count) + if (currentLength + lineBreaker.Current.PositionMeasure > measuredLength) { - currentPosition += lineBreaker.Current.PositionWrap; - - if (lineBreaker.Current.PositionWrap != currentRun.Length) + if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow) { - break; - } + if (lastWrapPosition > 0) + { + currentPosition = lastWrapPosition; - index++; + breakFound = true; + + break; + } + + //Find next possible wrap position (overflow) + if (index < textRuns.Count - 1) + { + if (lineBreaker.Current.PositionWrap != currentRun.Length) + { + //We already found the next possible wrap position. + breakFound = true; + + currentPosition = currentLength + lineBreaker.Current.PositionWrap; + + break; + } + + while (lineBreaker.MoveNext() && index < textRuns.Count) + { + currentPosition += lineBreaker.Current.PositionWrap; + + if (lineBreaker.Current.PositionWrap != currentRun.Length) + { + break; + } + + index++; + + if (index >= textRuns.Count) + { + break; + } + + currentRun = textRuns[index]; + + runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length); + + lineBreaker = new LineBreakEnumerator(runText); + } + } + else + { + currentPosition = currentLength + lineBreaker.Current.PositionWrap; + } + + breakFound = true; - if (index >= textRuns.Count) - { break; } - currentRun = textRuns[index]; + //We overflowed so we use the last available wrap position. + currentPosition = lastWrapPosition == 0 ? measuredLength : lastWrapPosition; - runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length); + breakFound = true; - lineBreaker = new LineBreakEnumerator(runText); + break; } - } - else - { - currentPosition = currentLength + lineBreaker.Current.PositionWrap; - } - breakFound = true; + if (lineBreaker.Current.PositionMeasure != lineBreaker.Current.PositionWrap) + { + lastWrapPosition = currentLength + lineBreaker.Current.PositionWrap; + } + } break; } - - //We overflowed so we use the last available wrap position. - currentPosition = lastWrapPosition == 0 ? measuredLength : lastWrapPosition; - - breakFound = true; - - break; - } - - if (lineBreaker.Current.PositionMeasure != lineBreaker.Current.PositionWrap) - { - lastWrapPosition = currentLength + lineBreaker.Current.PositionWrap; - } } if (!breakFound) @@ -694,7 +702,7 @@ namespace Avalonia.Media.TextFormatting var remainingCharacters = splitResult.Second; var lineBreak = remainingCharacters?.Count > 0 ? - new TextLineBreak(currentLineBreak?.TextEndOfLine, resolvedFlowDirection, remainingCharacters) : + new TextLineBreak(null, resolvedFlowDirection, remainingCharacters) : null; if (lineBreak is null && currentLineBreak?.TextEndOfLine != null) diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs b/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs index 42a84ec137..e30a0fe9f4 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLeadingPrefixCharacterEllipsis.cs @@ -123,7 +123,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 5a71bde522..a1f93bcd07 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -230,12 +230,12 @@ namespace Avalonia.Media.TextFormatting currentRun = _textRuns[j]; - if(currentRun is not ShapedTextCharacters) + if(currentRun is not ShapedTextRun) { continue; } - shapedRun = (ShapedTextCharacters)currentRun; + shapedRun = (ShapedTextRun)currentRun; if (currentDistance + shapedRun.Size.Width <= distance) { diff --git a/src/Avalonia.Base/Media/TextFormatting/TextRun.cs b/src/Avalonia.Base/Media/TextFormatting/TextRun.cs index 21f85b898f..56232ec9c8 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, _textRun.CharacterBufferReference.OffsetToFirstChar, _textRun.Length); + return new string(charsPtr, 0, _textRun.Length); } } }