Skip to content

Commit e5aff32

Browse files
xoofxMrJul
authored andcommitted
Fix TextLayout.Width calculation (#18305) (#18310)
* Fix TextLayout.Width calculation (#18305) * Use WinSymbols3.ttf
1 parent 719f1c3 commit e5aff32

File tree

4 files changed

+53
-11
lines changed

4 files changed

+53
-11
lines changed

src/Avalonia.Base/Media/TextFormatting/TextLayout.cs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -679,20 +679,47 @@ private TextLine[] CreateTextLines()
679679

680680
private void UpdateMetrics(TextLineImpl currentLine, ref bool first)
681681
{
682-
_metrics.InkBounds = _metrics.InkBounds.Union(new Rect(new Point(0, _metrics.Bounds.Bottom) + currentLine.InkBounds.Position, currentLine.InkBounds.Size));
683-
_metrics.Bounds = _metrics.Bounds.Union(new Rect(new Point(0, _metrics.Bounds.Bottom) + currentLine.Bounds.Position, currentLine.Bounds.Size));
682+
// 1) Offset each line’s bounding rectangles by the total height so far,
683+
// so we keep an overall bounding box for the entire text block.
684+
var lineTop = _metrics.Height;
684685

685-
_metrics.MinTextWidth = Math.Max(_metrics.MinTextWidth, currentLine.Bounds.Width);
686-
_metrics.MinTextWidth = Math.Max(_metrics.MinTextWidth, currentLine.InkBounds.Width);
686+
// Offset the line's Bounds
687+
var lineBoundsRect = new Rect(
688+
currentLine.Bounds.X,
689+
lineTop + currentLine.Bounds.Y,
690+
currentLine.Bounds.Width,
691+
currentLine.Bounds.Height);
687692

688-
_metrics.Height = _metrics.Bounds.Height;
689-
_metrics.Width = _metrics.InkBounds.Width;
690-
_metrics.WidthIncludingTrailingWhitespace = _metrics.Bounds.Width;
691-
_metrics.Extent = _metrics.InkBounds.Height;
692-
_metrics.OverhangLeading = Math.Max(0, _metrics.Bounds.Left - _metrics.InkBounds.Left);
693-
_metrics.OverhangTrailing = Math.Max(0, _metrics.InkBounds.Right - _metrics.Bounds.Right);
694-
_metrics.OverhangAfter = Math.Max(0, _metrics.InkBounds.Bottom - _metrics.Bounds.Bottom);
693+
_metrics.Bounds = _metrics.Bounds.Union(lineBoundsRect);
695694

695+
// Offset the line's InkBounds
696+
var lineInkRect = new Rect(
697+
currentLine.InkBounds.X,
698+
lineTop + currentLine.InkBounds.Y,
699+
currentLine.InkBounds.Width,
700+
currentLine.InkBounds.Height);
701+
702+
_metrics.InkBounds = _metrics.InkBounds.Union(lineInkRect);
703+
704+
// 2) Accumulate total layout height by adding the line’s Height.
705+
_metrics.Height += currentLine.Height;
706+
707+
// 3) For the layout’s Width and WidthIncludingTrailingWhitespace,
708+
// use the maximum of the line widths rather than the bounding box.
709+
_metrics.Width = Math.Max(_metrics.Width, currentLine.Width);
710+
_metrics.WidthIncludingTrailingWhitespace = Math.Max(_metrics.WidthIncludingTrailingWhitespace, currentLine.WidthIncludingTrailingWhitespace);
711+
712+
// 4) Extent is the max black-pixel extent among lines.
713+
_metrics.Extent = Math.Max(_metrics.Extent, currentLine.Extent);
714+
715+
// 5) We can track min-text-width or overhangs similarly if needed.
716+
_metrics.MinTextWidth = Math.Max(_metrics.MinTextWidth, currentLine.Width);
717+
718+
_metrics.OverhangLeading = Math.Max(_metrics.OverhangLeading, currentLine.OverhangLeading);
719+
_metrics.OverhangTrailing = Math.Max(_metrics.OverhangTrailing, currentLine.OverhangTrailing);
720+
_metrics.OverhangAfter = Math.Max(_metrics.OverhangAfter, currentLine.OverhangAfter);
721+
722+
// 6) Capture the baseline from the first line.
696723
if (first)
697724
{
698725
_metrics.Baseline = currentLine.Baseline;

tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
<EmbeddedResource Include="..\Avalonia.RenderTests\*\*.ttf" />
1313
<None Remove="Fonts\DejaVuSans.ttf" />
1414
<None Remove="Fonts\Manrope-Light.ttf" />
15+
<None Remove="Fonts\WinSymbols3.ttf" />
1516
<EmbeddedResource Include="Fonts\DejaVuSans.ttf" />
1617
<EmbeddedResource Include="Fonts\Manrope-Light.ttf" />
18+
<EmbeddedResource Include="Fonts\WinSymbols3.ttf" />
1719
</ItemGroup>
1820
<ItemGroup>
1921
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
Binary file not shown.

tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,19 @@ public void Should_Handle_TextStyle_With_Ligature()
11471147
}
11481148
}
11491149

1150+
[Fact]
1151+
public void Should_Measure_TextLayoutSymbolWithAndWidthIncludingTrailingWhitespace()
1152+
{
1153+
const string symbolsFont = "resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests#Symbols";
1154+
using (Start())
1155+
{
1156+
var textLayout = new TextLayout("\ue971", new Typeface(symbolsFont), 12.0, Brushes.White);
1157+
1158+
Assert.Equal(new Size(12.0, 12.0), new Size(textLayout.Width, textLayout.Height));
1159+
Assert.Equal(12.0, textLayout.WidthIncludingTrailingWhitespace);
1160+
}
1161+
}
1162+
11501163
private static IDisposable Start()
11511164
{
11521165
var disposable = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface

0 commit comments

Comments
 (0)