Browse Source

Fix BaselineAlignment (#16276)

* Implement remaining BaselineAlignment variants

* Adjust BaselineOffset calculation

* Draw all shaped runs at the baseline

* Random change please revert

* Revert change
pull/16321/head
Benedikt Stebner 2 years ago
committed by GitHub
parent
commit
376a84182e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 15
      src/Avalonia.Base/Media/TextDecoration.cs
  2. 5
      src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs
  3. 96
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  4. 2
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs

15
src/Avalonia.Base/Media/TextDecoration.cs

@ -182,18 +182,18 @@ namespace Avalonia.Media
break;
}
var origin = new Point();
var origin = baselineOrigin;
switch (Location)
{
case TextDecorationLocation.Baseline:
origin += glyphRun.BaselineOrigin;
case TextDecorationLocation.Overline:
origin += new Point(0, textMetrics.Ascent);
break;
case TextDecorationLocation.Strikethrough:
origin += new Point(baselineOrigin.X, baselineOrigin.Y + textMetrics.StrikethroughPosition);
origin += new Point(0, textMetrics.StrikethroughPosition);
break;
case TextDecorationLocation.Underline:
origin += new Point(baselineOrigin.X, baselineOrigin.Y + textMetrics.UnderlinePosition);
origin += new Point(0, textMetrics.UnderlinePosition);
break;
}
@ -255,7 +255,10 @@ namespace Avalonia.Media
}
}
drawingContext.DrawLine(pen, origin, origin + new Point(glyphRun.Metrics.Width, 0));
var p1 = origin;
var p2 = p1 + new Point(glyphRun.Metrics.Width, 0);
drawingContext.DrawLine(pen, p1, p2);
}
}
}

5
src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs

@ -64,7 +64,7 @@ namespace Avalonia.Media.TextFormatting
if (Properties.BackgroundBrush != null)
{
drawingContext.DrawRectangle(Properties.BackgroundBrush, null, GlyphRun.Bounds);
drawingContext.DrawRectangle(Properties.BackgroundBrush, null, GlyphRun.Bounds.Translate(new Vector(0, -Baseline)));
}
drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun);
@ -204,7 +204,8 @@ namespace Avalonia.Media.TextFormatting
ShapedBuffer.FontRenderingEmSize,
Text,
ShapedBuffer,
biDiLevel: BidiLevel);
biDiLevel: BidiLevel,
baselineOrigin: new Point());
}
public void Dispose()

96
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -115,18 +115,19 @@ namespace Avalonia.Media.TextFormatting
switch (baselineAlignment)
{
case BaselineAlignment.Baseline:
return textLine.Baseline;
case BaselineAlignment.Top:
return 0;
case BaselineAlignment.TextTop:
return textLine.Baseline - textLine.Extent + textRun.Size.Height / 2;
case BaselineAlignment.Center:
return textLine.Height / 2 - textRun.Size.Height / 2;
return textLine.Height / 2 + baseline - textRun.Size.Height / 2;
case BaselineAlignment.Subscript:
case BaselineAlignment.Bottom:
return textLine.Height - textRun.Size.Height;
case BaselineAlignment.Baseline:
case BaselineAlignment.TextTop:
case BaselineAlignment.TextBottom:
case BaselineAlignment.Subscript:
return textLine.Height - textRun.Size.Height + baseline;
case BaselineAlignment.Superscript:
return textLine.Baseline - baseline;
return baseline;
default:
throw new ArgumentOutOfRangeException(nameof(baselineAlignment), baselineAlignment, null);
}
@ -1143,7 +1144,6 @@ namespace Avalonia.Media.TextFormatting
}
TextRun? currentRun = null;
TextRun? previousRun = null;
while (runIndex < _indexedTextRuns.Count)
{
@ -1182,7 +1182,7 @@ namespace Avalonia.Media.TextFormatting
break;
}
case TextRun:
case not null:
{
if(direction == LogicalDirection.Forward)
{
@ -1212,8 +1212,6 @@ namespace Avalonia.Media.TextFormatting
}
runIndex++;
previousRun = currentRun;
}
return currentRun;
@ -1242,61 +1240,57 @@ namespace Avalonia.Media.TextFormatting
switch (_textRuns[index])
{
case ShapedTextRun textRun:
{
var textMetrics = textRun.TextMetrics;
var glyphRun = textRun.GlyphRun;
var runBounds = glyphRun.InkBounds.WithX(widthIncludingWhitespace + glyphRun.InkBounds.X);
{
var textMetrics = textRun.TextMetrics;
var glyphRun = textRun.GlyphRun;
var runBounds = glyphRun.InkBounds.WithX(widthIncludingWhitespace + glyphRun.InkBounds.X);
bounds = bounds.Union(runBounds);
bounds = bounds.Union(runBounds);
if (fontRenderingEmSize < textMetrics.FontRenderingEmSize)
{
fontRenderingEmSize = textMetrics.FontRenderingEmSize;
if (ascent > textMetrics.Ascent)
{
ascent = textMetrics.Ascent;
}
if (ascent > textMetrics.Ascent)
{
ascent = textMetrics.Ascent;
}
if (descent < textMetrics.Descent)
{
descent = textMetrics.Descent;
}
if (descent < textMetrics.Descent)
{
descent = textMetrics.Descent;
}
if (lineGap < textMetrics.LineGap)
{
lineGap = textMetrics.LineGap;
}
if (lineGap < textMetrics.LineGap)
{
lineGap = textMetrics.LineGap;
}
if (descent - ascent + lineGap > height)
{
height = descent - ascent + lineGap;
}
if (descent - ascent + lineGap > height)
{
height = descent - ascent + lineGap;
}
}
widthIncludingWhitespace += textRun.Size.Width;
widthIncludingWhitespace += textRun.Size.Width;
break;
}
break;
}
case DrawableTextRun drawableTextRun:
{
widthIncludingWhitespace += drawableTextRun.Size.Width;
if (drawableTextRun.Size.Height > height)
{
widthIncludingWhitespace += drawableTextRun.Size.Width;
height = drawableTextRun.Size.Height;
}
if (drawableTextRun.Size.Height > height)
{
height = drawableTextRun.Size.Height;
}
//Adjust current ascent so drawables and text align at the bottom edge of the line.
var offset = Math.Max(0, drawableTextRun.Baseline + ascent - descent);
//Adjust current ascent so drawables and text align at the bottom edge of the line.
var offset = Math.Max(0, drawableTextRun.Baseline + ascent - descent);
ascent -= offset;
ascent -= offset;
bounds = bounds.Union(new Rect(new Point(bounds.Right, 0), drawableTextRun.Size));
bounds = bounds.Union(new Rect(new Point(bounds.Right, 0), drawableTextRun.Size));
break;
}
break;
}
}
}

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

@ -1123,7 +1123,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var rect = textLayout.HitTestTextPosition(text.Length);
Assert.Equal(14.0625, rect.Top);
Assert.Equal(16.32, rect.Top);
}
}

Loading…
Cancel
Save