diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index 16fcf1eed98..0afafe44b87 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -162,7 +162,7 @@ public class TextBlock : Control, IInlineHost nameof(Inlines), t => t.Inlines, (t, v) => t.Inlines = v); private TextLayout? _textLayout; - protected Size _constraint; + protected Size _constraint = Size.Infinity; protected IReadOnlyList? _textRuns; private InlineCollection? _inlines; @@ -653,7 +653,7 @@ protected virtual TextLayout CreateTextLayout(string? text) TextDecorations, Foreground); - var paragraphProperties = new GenericTextParagraphProperties(FlowDirection, TextAlignment, true, false, + var paragraphProperties = new GenericTextParagraphProperties(FlowDirection, IsMeasureValid ? TextAlignment : TextAlignment.Left, true, false, defaultProperties, TextWrapping, LineHeight, 0, LetterSpacing) { LineSpacing = LineSpacing @@ -701,13 +701,19 @@ protected override Size MeasureOverride(Size availableSize) { var scale = LayoutHelper.GetLayoutScale(this); var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale); + var deflatedSize = availableSize.Deflate(padding); - _constraint = availableSize.Deflate(padding); - - //Reset TextLayout otherwise constraint might be outdated. - _textLayout?.Dispose(); - _textLayout = null; + if (_constraint != deflatedSize) + { + //Reset TextLayout when the constraint is not matching. + _textLayout?.Dispose(); + _textLayout = null; + _constraint = deflatedSize; + //Force arrange so text will be properly alligned. + InvalidateArrange(); + } + var inlines = Inlines; if (HasComplexContent) @@ -722,9 +728,14 @@ protected override Size MeasureOverride(Size availableSize) _textRuns = textRuns; } - var width = TextLayout.OverhangLeading + TextLayout.WidthIncludingTrailingWhitespace + TextLayout.OverhangTrailing; + //This implicitly recreated the TextLayout with a new constraint if we previously reset it. + var textLayout = TextLayout; + + var width = textLayout.OverhangLeading + textLayout.WidthIncludingTrailingWhitespace + textLayout.OverhangTrailing; + + var size = LayoutHelper.RoundLayoutSizeUp(new Size(width, textLayout.Height).Inflate(padding), 1, 1); - return new Size(width, TextLayout.Height).Inflate(padding); + return size; } protected override Size ArrangeOverride(Size finalSize) @@ -732,19 +743,24 @@ protected override Size ArrangeOverride(Size finalSize) var scale = LayoutHelper.GetLayoutScale(this); var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale); - //Fixes: #11019 - if (finalSize.Width < _constraint.Width) - { - _textLayout?.Dispose(); - _textLayout = null; - _constraint = finalSize.Deflate(padding); - } + var availableSize = finalSize.Deflate(padding); + + //ToDo: Introduce a text run cache to be able to reuse shaped runs etc. + _textLayout?.Dispose(); + _textLayout = null; + _constraint = availableSize; + + //This implicitly recreated the TextLayout with a new constraint. + var textLayout = TextLayout; if (HasComplexContent) - { + { + //Clear visual children before complex run arrangement + VisualChildren.Clear(); + var currentY = padding.Top; - foreach (var textLine in TextLayout.TextLines) + foreach (var textLine in textLayout.TextLines) { var currentX = padding.Left + textLine.Start; @@ -755,6 +771,10 @@ protected override Size ArrangeOverride(Size finalSize) if (drawable is EmbeddedControlRun controlRun && controlRun.Control is Control control) { + //Add again to prevent clipping + //Fixes: #17194 + VisualChildren.Add(control); + control.Arrange( new Rect(new Point(currentX, currentY), new Size(control.DesiredSize.Width, textLine.Height))); @@ -946,6 +966,6 @@ public InlinesTextSource(IReadOnlyList textRuns, IReadOnlyList