diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
index 73ec055bbe..26e73cdf3b 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
@@ -407,6 +407,7 @@ namespace Avalonia.Media.TextFormatting
var currentPosition = FirstTextSourceIndex;
var currentRect = Rect.Empty;
var startX = Start;
+ var runStart = startX;
//A portion of the line is covered.
for (var index = 0; index < TextRuns.Count; index++)
@@ -431,7 +432,7 @@ namespace Avalonia.Media.TextFormatting
{
case ShapedTextCharacters when currentRun is ShapedTextCharacters:
{
- if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End)
+ if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End && _flowDirection == FlowDirection.LeftToRight)
{
goto skip;
}
@@ -480,7 +481,7 @@ namespace Avalonia.Media.TextFormatting
case ShapedTextCharacters shapedRun:
{
endOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit(
- shapedRun.ShapedBuffer.IsLeftToRight ?
+ shapedRun.ShapedBuffer.IsLeftToRight ?
new CharacterHit(firstTextSourceCharacterIndex + textLength) :
new CharacterHit(firstTextSourceCharacterIndex));
@@ -493,7 +494,7 @@ namespace Avalonia.Media.TextFormatting
startX += startOffset;
- var characterHit = shapedRun.GlyphRun.IsLeftToRight ?
+ var characterHit = _flowDirection == FlowDirection.LeftToRight ?
shapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _) :
shapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
@@ -580,6 +581,11 @@ namespace Avalonia.Media.TextFormatting
{
break;
}
+
+ if (_flowDirection == FlowDirection.RightToLeft)
+ {
+ endX += currentRun.Size.Width - endOffset;
+ }
}
else
{
@@ -591,8 +597,9 @@ namespace Avalonia.Media.TextFormatting
endX += currentRun.Size.Width - endOffset;
}
- lastDirection = currentDirection;
startX = endX;
+ lastDirection = currentDirection;
+ runStart += currentRun.Size.Width;
}
return result;
diff --git a/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs b/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs
index a7fe92dc9a..4e75bb921e 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs
@@ -16,7 +16,7 @@ namespace Avalonia.Media.TextFormatting
{
Typeface = typeface;
FontRenderingEmSize = fontRenderingEmSize;
- BidLevel = bidiLevel;
+ BidiLevel = bidiLevel;
Culture = culture;
IncrementalTabWidth = incrementalTabWidth;
}
@@ -33,7 +33,7 @@ namespace Avalonia.Media.TextFormatting
///
/// Get the bidi level of the text.
///
- public sbyte BidLevel { get; }
+ public sbyte BidiLevel { get; }
///
/// Get the culture.
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index 0785149a73..62ea05c68c 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -515,11 +515,6 @@ namespace Avalonia.Controls.Presenters
protected override Size MeasureOverride(Size availableSize)
{
- if (string.IsNullOrEmpty(Text))
- {
- return new Size();
- }
-
_constraint = availableSize;
_textLayout = null;
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index bbe6aeb7ee..1a69d1218c 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -631,7 +631,11 @@ namespace Avalonia.Controls
return finalSize;
}
- _constraint = new Size(finalSize.Width, double.PositiveInfinity);
+ var scale = LayoutHelper.GetLayoutScale(this);
+
+ var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale);
+
+ _constraint = new Size(finalSize.Deflate(padding).Width, double.PositiveInfinity);
_textLayout = null;
diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs
index 083b16c107..22ff8e8f97 100644
--- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs
+++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs
@@ -137,7 +137,7 @@ namespace Avalonia.Headless
{
var typeface = options.Typeface;
var fontRenderingEmSize = options.FontRenderingEmSize;
- var bidiLevel = options.BidLevel;
+ var bidiLevel = options.BidiLevel;
return new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);
}
diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs
index 908b0ffa47..777e907617 100644
--- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs
+++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs
@@ -16,7 +16,7 @@ namespace Avalonia.Skia
{
var typeface = options.Typeface;
var fontRenderingEmSize = options.FontRenderingEmSize;
- var bidiLevel = options.BidLevel;
+ var bidiLevel = options.BidiLevel;
var culture = options.Culture;
using (var buffer = new Buffer())
diff --git a/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
index f4e4b00147..6e32d32913 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
@@ -16,7 +16,7 @@ namespace Avalonia.Direct2D1.Media
{
var typeface = options.Typeface;
var fontRenderingEmSize = options.FontRenderingEmSize;
- var bidiLevel = options.BidLevel;
+ var bidiLevel = options.BidiLevel;
var culture = options.Culture;
using (var buffer = new Buffer())
diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
index a47638d2ec..f29dddf86b 100644
--- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
+++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
@@ -718,31 +718,45 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
- var text = "0123".AsMemory();
- var ltrOptions = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 0, CultureInfo.CurrentCulture);
- var rtlOptions = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 1, CultureInfo.CurrentCulture);
-
- var textRuns = new List
- {
- new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text), ltrOptions), defaultProperties),
- new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text, text.Length, text.Length), ltrOptions), defaultProperties),
- new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text, text.Length * 2, text.Length), rtlOptions), defaultProperties),
- new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text, text.Length * 3, text.Length), ltrOptions), defaultProperties)
- };
-
-
- var textSource = new FixedRunsTextSource(textRuns);
+ var text = "אאא AAA";
+ var textSource = new SingleBufferTextSource(text, defaultProperties);
var formatter = new TextFormatterImpl();
var textLine =
- formatter.FormatLine(textSource, 0, double.PositiveInfinity,
- new GenericTextParagraphProperties(defaultProperties));
+ formatter.FormatLine(textSource, 0, 200,
+ new GenericTextParagraphProperties(FlowDirection.RightToLeft, TextAlignment.Left, true, true, defaultProperties, TextWrapping.NoWrap, 0, 0));
- var textBounds = textLine.GetTextBounds(0, text.Length * 4);
+ var textBounds = textLine.GetTextBounds(0, text.Length);
- Assert.Equal(3, textBounds.Count);
+ Assert.Equal(2, textBounds.Count);
Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width));
+
+ textBounds = textLine.GetTextBounds(0, 4);
+
+ var secondRun = textLine.TextRuns[1] as ShapedTextCharacters;
+
+ 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;
+
+ Assert.Equal(1, textBounds.Count);
+ Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
+
+ textBounds = textLine.GetTextBounds(0, 5);
+
+ Assert.Equal(2, textBounds.Count);
+
+ Assert.Equal(7.201171875, textBounds[0].Rectangle.Width);
+
+ Assert.Equal(textLine.Start, textBounds[0].Rectangle.Left);
+
+ Assert.Equal(secondRun.Size.Width, textBounds[1].Rectangle.Width);
+
+ Assert.Equal(textLine.Start + firstRun.Size.Width, textBounds[1].Rectangle.Left);
}
}
diff --git a/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs b/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs
index 5f8854b3ab..4bc30484e9 100644
--- a/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs
+++ b/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs
@@ -15,7 +15,7 @@ namespace Avalonia.UnitTests
{
var typeface = options.Typeface;
var fontRenderingEmSize = options.FontRenderingEmSize;
- var bidiLevel = options.BidLevel;
+ var bidiLevel = options.BidiLevel;
var culture = options.Culture;
using (var buffer = new Buffer())
diff --git a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs
index c4b1e6c154..7c34bd192e 100644
--- a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs
+++ b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs
@@ -11,7 +11,7 @@ namespace Avalonia.UnitTests
{
var typeface = options.Typeface;
var fontRenderingEmSize = options.FontRenderingEmSize;
- var bidiLevel = options.BidLevel;
+ var bidiLevel = options.BidiLevel;
var shapedBuffer = new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);