Browse Source

Rework GlyphRun BaselineOrigin

pull/4635/head
Benedikt Schroeder 5 years ago
parent
commit
c2fad766e5
  1. 3
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  2. 4
      src/Avalonia.Controls/Primitives/AccessText.cs
  3. 5
      src/Avalonia.Controls/TextBlock.cs
  4. 2
      src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  5. 20
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  6. 5
      src/Avalonia.Visuals/Media/DrawingContext.cs
  7. 49
      src/Avalonia.Visuals/Media/GlyphRun.cs
  8. 13
      src/Avalonia.Visuals/Media/GlyphRunDrawing.cs
  9. 17
      src/Avalonia.Visuals/Media/TextDecoration.cs
  10. 7
      src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs
  11. 11
      src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
  12. 6
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
  13. 17
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  14. 3
      src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
  15. 29
      src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
  16. 2
      src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs
  17. 3
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  18. 4
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  19. 13
      src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs
  20. 8
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  21. 7
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  22. 2
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs

3
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -61,7 +61,6 @@ namespace RenderDemo.Pages
{
Foreground = Brushes.Black,
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices),
BaselineOrigin = new Point(0, -_glyphTypeface.Ascent * scale)
};
drawingGroup.Children.Add(glyphRunDrawing);
@ -69,7 +68,7 @@ namespace RenderDemo.Pages
var geometryDrawing = new GeometryDrawing
{
Pen = new Pen(Brushes.Black),
Geometry = new RectangleGeometry { Rect = glyphRunDrawing.GlyphRun.Bounds }
Geometry = new RectangleGeometry { Rect = new Rect(glyphRunDrawing.GlyphRun.Size) }
};
drawingGroup.Children.Add(geometryDrawing);

4
src/Avalonia.Controls/Primitives/AccessText.cs

@ -126,7 +126,7 @@ namespace Avalonia.Controls.Primitives
if (shapedTextCharacters.GlyphRun.Characters.End < textPosition)
{
currentX += shapedTextCharacters.GlyphRun.Bounds.Width;
currentX += shapedTextCharacters.Size.Width;
continue;
}
@ -143,7 +143,7 @@ namespace Avalonia.Controls.Primitives
width = 0.0;
}
return new Rect(currentX, currentY, width, shapedTextCharacters.GlyphRun.Bounds.Height);
return new Rect(currentX, currentY, width, shapedTextCharacters.Size.Height);
}
}

5
src/Avalonia.Controls/TextBlock.cs

@ -434,7 +434,10 @@ namespace Avalonia.Controls
var padding = Padding;
TextLayout.Draw(context, new Point(padding.Left + offsetX, padding.Top));
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top)))
{
TextLayout.Draw(context);
}
}
/// <summary>

2
src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -385,7 +385,7 @@ namespace Avalonia.Headless
}
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
}

20
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -1,15 +1,33 @@
Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.GlyphRunDrawing.BaselineOrigin.set(Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotSealType : Type 'Avalonia.Media.Typeface' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract.
TypeCannotChangeClassification : Type 'Avalonia.Media.Typeface' is a 'struct' in the implementation but is a 'class' in the contract.
CannotMakeMemberNonVirtual : Member 'public System.Boolean Avalonia.Media.Typeface.Equals(System.Object)' is non-virtual in the implementation but is virtual in the contract.
CannotMakeMemberNonVirtual : Member 'public System.Int32 Avalonia.Media.Typeface.GetHashCode()' is non-virtual in the implementation but is virtual in the contract.
TypesMustExist : Type 'Avalonia.Media.Fonts.FontKey' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.DrawableTextRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size.get()' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.ShapedTextCharacters.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.ShapedTextCharacters.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLayout.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak' is abstract in the implementation but is missing in the contract.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.LineBreak.get()' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak.get()' is abstract in the implementation but is missing in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
Total Issues: 13
Total Issues: 31

5
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -206,14 +206,13 @@ namespace Avalonia.Media
/// </summary>
/// <param name="foreground">The foreground brush.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin">The baseline origin of the glyph run.</param>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
Contract.Requires<ArgumentNullException>(glyphRun != null);
if (foreground != null)
{
PlatformImpl.DrawGlyphRun(foreground, glyphRun, baselineOrigin);
PlatformImpl.DrawGlyphRun(foreground, glyphRun);
}
}

49
src/Avalonia.Visuals/Media/GlyphRun.cs

@ -16,8 +16,9 @@ namespace Avalonia.Media
private IGlyphRunImpl _glyphRunImpl;
private GlyphTypeface _glyphTypeface;
private double _fontRenderingEmSize;
private Rect? _bounds;
private Size? _size;
private int _biDiLevel;
private Point? _baselineOrigin;
private ReadOnlySlice<ushort> _glyphIndices;
private ReadOnlySlice<double> _glyphAdvances;
@ -89,6 +90,20 @@ namespace Avalonia.Media
set => Set(ref _fontRenderingEmSize, value);
}
/// <summary>
/// Gets or sets the baseline origin of the<see cref="GlyphRun"/>.
/// </summary>
public Point BaselineOrigin
{
get
{
_baselineOrigin ??= CalculateBaselineOrigin();
return _baselineOrigin.Value;
}
set => Set(ref _baselineOrigin, value);
}
/// <summary>
/// Gets or sets an array of <see cref="ushort"/> values that represent the glyph indices in the rendering physical font.
/// </summary>
@ -156,16 +171,13 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets the conservative bounding box of the <see cref="GlyphRun"/>.
/// </summary>
public Rect Bounds
public Size Size
{
get
{
if (_bounds == null)
{
_bounds = CalculateBounds();
}
_size ??= CalculateSize();
return _bounds.Value;
return _size.Value;
}
}
@ -200,7 +212,7 @@ namespace Avalonia.Media
if (characterHit.FirstCharacterIndex + characterHit.TrailingLength > Characters.End)
{
return Bounds.Width;
return Size.Width;
}
var glyphIndex = FindGlyphIndex(characterHit.FirstCharacterIndex);
@ -257,7 +269,7 @@ namespace Avalonia.Media
}
//After
if (distance > Bounds.Size.Width)
if (distance > Size.Width)
{
isInside = false;
@ -529,12 +541,21 @@ namespace Avalonia.Media
}
/// <summary>
/// Calculates the bounds of the <see cref="GlyphRun"/>.
/// Calculates the default baseline origin of the <see cref="GlyphRun"/>.
/// </summary>
/// <returns>The baseline origin.</returns>
private Point CalculateBaselineOrigin()
{
return new Point(0, -GlyphTypeface.Ascent * Scale);
}
/// <summary>
/// Calculates the size of the <see cref="GlyphRun"/>.
/// </summary>
/// <returns>
/// The calculated bounds.
/// </returns>
private Rect CalculateBounds()
private Size CalculateSize()
{
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
@ -555,7 +576,7 @@ namespace Avalonia.Media
}
}
return new Rect(0, GlyphTypeface.Ascent * Scale, width, height);
return new Size(width, height);
}
private void Set<T>(ref T field, T value)
@ -590,11 +611,15 @@ namespace Avalonia.Media
throw new InvalidOperationException();
}
_baselineOrigin = new Point(0, -GlyphTypeface.Ascent * Scale);
var platformRenderInterface = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
_glyphRunImpl = platformRenderInterface.CreateGlyphRun(this, out var width);
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
_size = new Size(width, height);
}
void IDisposable.Dispose()

13
src/Avalonia.Visuals/Media/GlyphRunDrawing.cs

@ -8,9 +8,6 @@
public static readonly StyledProperty<GlyphRun> GlyphRunProperty =
AvaloniaProperty.Register<GlyphRunDrawing, GlyphRun>(nameof(GlyphRun));
public static readonly StyledProperty<Point> BaselineOriginProperty =
AvaloniaProperty.Register<GlyphRunDrawing, Point>(nameof(BaselineOrigin));
public IBrush Foreground
{
get => GetValue(ForegroundProperty);
@ -23,12 +20,6 @@
set => SetValue(GlyphRunProperty, value);
}
public Point BaselineOrigin
{
get => GetValue(BaselineOriginProperty);
set => SetValue(BaselineOriginProperty, value);
}
public override void Draw(DrawingContext context)
{
if (GlyphRun == null)
@ -36,12 +27,12 @@
return;
}
context.DrawGlyphRun(Foreground, GlyphRun, BaselineOrigin);
context.DrawGlyphRun(Foreground, GlyphRun);
}
public override Rect GetBounds()
{
return GlyphRun?.Bounds ?? default;
return GlyphRun != null ? new Rect(GlyphRun.Size) : Rect.Empty;
}
}
}

17
src/Avalonia.Visuals/Media/TextDecoration.cs

@ -155,8 +155,7 @@ namespace Avalonia.Media
/// </summary>
/// <param name="drawingContext">The drawing context.</param>
/// <param name="shapedTextCharacters">The shaped characters that are decorated.</param>
/// <param name="origin">The origin.</param>
internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters, Point origin)
internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters)
{
var fontRenderingEmSize = shapedTextCharacters.Properties.FontRenderingEmSize;
var fontMetrics = shapedTextCharacters.FontMetrics;
@ -181,16 +180,20 @@ namespace Avalonia.Media
break;
}
var origin = new Point();
switch (Location)
{
case TextDecorationLocation.Overline:
origin += new Point(0, fontMetrics.Ascent);
case TextDecorationLocation.Baseline:
origin += shapedTextCharacters.GlyphRun.BaselineOrigin;
break;
case TextDecorationLocation.Strikethrough:
origin += new Point(0, -fontMetrics.StrikethroughPosition);
origin += new Point(shapedTextCharacters.GlyphRun.BaselineOrigin.X,
shapedTextCharacters.GlyphRun.BaselineOrigin.Y - fontMetrics.StrikethroughPosition);
break;
case TextDecorationLocation.Underline:
origin += new Point(0, -fontMetrics.UnderlinePosition);
origin += new Point(shapedTextCharacters.GlyphRun.BaselineOrigin.X,
shapedTextCharacters.GlyphRun.BaselineOrigin.Y - fontMetrics.UnderlinePosition);
break;
}
@ -207,7 +210,7 @@ namespace Avalonia.Media
var pen = new Pen(Stroke ?? shapedTextCharacters.Properties.ForegroundBrush, thickness,
new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap);
drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Bounds.Width, 0));
drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Size.Width, 0));
}
}
}

7
src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs

@ -6,15 +6,14 @@
public abstract class DrawableTextRun : TextRun
{
/// <summary>
/// Gets the bounds.
/// Gets the size.
/// </summary>
public abstract Rect Bounds { get; }
public abstract Size Size { get; }
/// <summary>
/// Draws the <see cref="DrawableTextRun"/> at the given origin.
/// </summary>
/// <param name="drawingContext">The drawing context.</param>
/// <param name="origin">The origin.</param>
public abstract void Draw(DrawingContext drawingContext, Point origin);
public abstract void Draw(DrawingContext drawingContext);
}
}

11
src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs

@ -26,7 +26,7 @@ namespace Avalonia.Media.TextFormatting
public override int TextSourceLength { get; }
/// <inheritdoc/>
public override Rect Bounds => GlyphRun.Bounds;
public override Size Size => GlyphRun.Size;
/// <summary>
/// Gets the font metrics.
@ -45,7 +45,7 @@ namespace Avalonia.Media.TextFormatting
public GlyphRun GlyphRun { get; }
/// <inheritdoc/>
public override void Draw(DrawingContext drawingContext, Point origin)
public override void Draw(DrawingContext drawingContext)
{
if (GlyphRun.GlyphIndices.Length == 0)
{
@ -64,11 +64,10 @@ namespace Avalonia.Media.TextFormatting
if (Properties.BackgroundBrush != null)
{
drawingContext.DrawRectangle(Properties.BackgroundBrush, null,
new Rect(origin.X, origin.Y + FontMetrics.Ascent, Bounds.Width, Bounds.Height));
drawingContext.DrawRectangle(Properties.BackgroundBrush, null, new Rect(Size));
}
drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun, origin);
drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun);
if (Properties.TextDecorations == null)
{
@ -77,7 +76,7 @@ namespace Avalonia.Media.TextFormatting
foreach (var textDecoration in Properties.TextDecorations)
{
textDecoration.Draw(drawingContext, this, origin);
textDecoration.Draw(drawingContext, this);
}
}

6
src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs

@ -52,7 +52,7 @@ namespace Avalonia.Media.TextFormatting
{
var glyphRun = textCharacters.GlyphRun;
if (glyphRun.Bounds.Width < availableWidth)
if (glyphRun.Size.Width < availableWidth)
{
return glyphRun.Characters.Length;
}
@ -348,7 +348,7 @@ namespace Avalonia.Media.TextFormatting
{
var currentRun = textRuns[runIndex];
if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
if (currentWidth + currentRun.Size.Width > availableWidth)
{
var measuredLength = MeasureCharacters(currentRun, paragraphWidth - currentWidth);
@ -421,7 +421,7 @@ namespace Avalonia.Media.TextFormatting
return new TextLineImpl(splitResult.First, textLineMetrics, lineBreak);
}
currentWidth += currentRun.GlyphRun.Bounds.Width;
currentWidth += currentRun.Size.Width;
currentLength += currentRun.GlyphRun.Characters.Length;

17
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@ -115,22 +115,27 @@ namespace Avalonia.Media.TextFormatting
/// Draws the text layout.
/// </summary>
/// <param name="context">The drawing context.</param>
/// <param name="origin">The origin.</param>
public void Draw(DrawingContext context, Point origin)
public void Draw(DrawingContext context)
{
if (!TextLines.Any())
{
return;
}
var currentY = origin.Y;
var currentY = 0.0;
foreach (var textLine in TextLines)
{
var offsetX = TextLine.GetParagraphOffsetX(textLine.LineMetrics.Size.Width, Size.Width,
_paragraphProperties.TextAlignment);
using (context.PushPostTransform(Matrix.CreateTranslation(0, currentY)))
{
var offsetX = TextLine.GetParagraphOffsetX(textLine.LineMetrics.Size.Width, Size.Width,
_paragraphProperties.TextAlignment);
textLine.Draw(context, new Point(origin.X + offsetX, currentY));
using (context.PushPostTransform(Matrix.CreateTranslation(offsetX, 0)))
{
textLine.Draw(context);
}
}
currentY += textLine.LineMetrics.Size.Height;
}

3
src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs

@ -51,8 +51,7 @@ namespace Avalonia.Media.TextFormatting
/// Draws the <see cref="TextLine"/> at the given origin.
/// </summary>
/// <param name="drawingContext">The drawing context.</param>
/// <param name="origin">The origin.</param>
public abstract void Draw(DrawingContext drawingContext, Point origin);
public abstract void Draw(DrawingContext drawingContext);
/// <summary>
/// Create a collapsed line based on collapsed text properties.

29
src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs

@ -33,17 +33,18 @@ namespace Avalonia.Media.TextFormatting
public override bool HasCollapsed { get; }
/// <inheritdoc/>
public override void Draw(DrawingContext drawingContext, Point origin)
public override void Draw(DrawingContext drawingContext)
{
var currentX = origin.X;
var currentX = 0.0;
foreach (var textRun in _textRuns)
{
var baselineOrigin = new Point(currentX, origin.Y + LineMetrics.TextBaseline);
textRun.Draw(drawingContext, baselineOrigin);
using (drawingContext.PushPostTransform(Matrix.CreateTranslation(currentX, 0)))
{
textRun.Draw(drawingContext);
}
currentX += textRun.Bounds.Width;
currentX += textRun.Size.Width;
}
}
@ -64,13 +65,13 @@ namespace Avalonia.Media.TextFormatting
var shapedSymbol = CreateShapedSymbol(collapsingProperties.Symbol);
var availableWidth = collapsingProperties.Width - shapedSymbol.Bounds.Width;
var availableWidth = collapsingProperties.Width - shapedSymbol.Size.Width;
while (runIndex < _textRuns.Count)
{
var currentRun = _textRuns[runIndex];
currentWidth += currentRun.GlyphRun.Bounds.Width;
currentWidth += currentRun.Size.Width;
if (currentWidth > availableWidth)
{
@ -125,7 +126,7 @@ namespace Avalonia.Media.TextFormatting
return new TextLineImpl(shapedTextCharacters, textLineMetrics, TextLineBreak, true);
}
availableWidth -= currentRun.GlyphRun.Bounds.Width;
availableWidth -= currentRun.Size.Width;
collapsedLength += currentRun.GlyphRun.Characters.Length;
@ -133,7 +134,7 @@ namespace Avalonia.Media.TextFormatting
}
textLineMetrics =
new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Bounds.Width),
new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Size.Width),
LineMetrics.TextBaseline, TextRange, LineMetrics.HasOverflowed);
return new TextLineImpl(new List<ShapedTextCharacters>(_textRuns) { shapedSymbol }, textLineMetrics, null,
@ -156,12 +157,12 @@ namespace Avalonia.Media.TextFormatting
{
characterHit = run.GlyphRun.GetCharacterHitFromDistance(distance, out _);
if (distance <= run.Bounds.Width)
if (distance <= run.Size.Width)
{
break;
}
distance -= run.Bounds.Width;
distance -= run.Size.Width;
}
return characterHit;
@ -229,7 +230,7 @@ namespace Avalonia.Media.TextFormatting
{
if (codepointIndex > textRun.Text.End)
{
currentDistance += textRun.Bounds.Width;
currentDistance += textRun.Size.Width;
continue;
}
@ -405,7 +406,7 @@ namespace Avalonia.Media.TextFormatting
for (var i = 0; i < shapedTextCharacters.Count; i++)
{
shapedWidth += shapedTextCharacters[i].Bounds.Width;
shapedWidth += shapedTextCharacters[i].Size.Width;
}
return shapedWidth;

2
src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs

@ -67,7 +67,7 @@ namespace Avalonia.Media.TextFormatting
var fontMetrics =
new FontMetrics(shapedRun.Properties.Typeface, shapedRun.Properties.FontRenderingEmSize);
lineWidth += shapedRun.Bounds.Width;
lineWidth += shapedRun.Size.Width;
if (ascent > fontMetrics.Ascent)
{

3
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@ -84,8 +84,7 @@ namespace Avalonia.Platform
/// </summary>
/// <param name="foreground">The foreground.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin">The baseline origin of the glyph run.</param>
void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin);
void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun);
/// <summary>
/// Creates a new <see cref="IRenderTargetBitmapImpl"/> that can be used as a render layer

4
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@ -204,13 +204,13 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
var next = NextDrawAs<GlyphRunNode>();
if (next == null || !next.Item.Equals(Transform, foreground, glyphRun))
{
Add(new GlyphRunNode(Transform, foreground, glyphRun, baselineOrigin, CreateChildScene(foreground)));
Add(new GlyphRunNode(Transform, foreground, glyphRun, CreateChildScene(foreground)));
}
else

13
src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.VisualTree;
@ -17,20 +18,17 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="transform">The transform.</param>
/// <param name="foreground">The foreground brush.</param>
/// <param name="glyphRun">The glyph run to draw.</param>
/// <param name="baselineOrigin">The baseline origin of the glyph run.</param>
/// <param name="childScenes">Child scenes for drawing visual brushes.</param>
public GlyphRunNode(
Matrix transform,
IBrush foreground,
GlyphRun glyphRun,
Point baselineOrigin,
IDictionary<IVisual, Scene> childScenes = null)
: base(glyphRun.Bounds.Translate(baselineOrigin), transform)
: base(new Rect(glyphRun.Size), transform)
{
Transform = transform;
Foreground = foreground?.ToImmutable();
GlyphRun = glyphRun;
BaselineOrigin = baselineOrigin;
ChildScenes = childScenes;
}
@ -49,11 +47,6 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary>
public GlyphRun GlyphRun { get; }
/// <summary>
/// Gets the baseline origin.
/// </summary>
public Point BaselineOrigin { get; set; }
/// <inheritdoc/>
public override IDictionary<IVisual, Scene> ChildScenes { get; }
@ -61,7 +54,7 @@ namespace Avalonia.Rendering.SceneGraph
public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawGlyphRun(Foreground, GlyphRun, BaselineOrigin);
context.DrawGlyphRun(Foreground, GlyphRun);
}
/// <summary>

8
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -401,16 +401,16 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Bounds.Size))
using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl;
ConfigureTextRendering(paintWrapper);
Canvas.DrawText(glyphRunImpl.TextBlob, (float)baselineOrigin.X,
(float)baselineOrigin.Y, paintWrapper.Paint);
Canvas.DrawText(glyphRunImpl.TextBlob, (float)glyphRun.BaselineOrigin.X,
(float)glyphRun.BaselineOrigin.Y, paintWrapper.Paint);
}
}

7
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -324,13 +324,14 @@ namespace Avalonia.Direct2D1.Media
/// <param name="foreground">The foreground.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin"></param>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
using (var brush = CreateBrush(foreground, glyphRun.Bounds.Size))
using (var brush = CreateBrush(foreground, glyphRun.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl;
_renderTarget.DrawGlyphRun(baselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun, brush.PlatformBrush, MeasuringMode.Natural);
_renderTarget.DrawGlyphRun(glyphRun.BaselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun,
brush.PlatformBrush, MeasuringMode.Natural);
}
}

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

@ -369,7 +369,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var glyphRun = shapedRun.GlyphRun;
var width = glyphRun.Bounds.Width;
var width = glyphRun.Size.Width;
var characterHit = glyphRun.GetCharacterHitFromDistance(width, out _);

Loading…
Cancel
Save