diff --git a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs index 7f15845596..ddee880288 100644 --- a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs +++ b/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); diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs index 89f672deaa..7a5e6ce426 100644 --- a/src/Avalonia.Controls/Primitives/AccessText.cs +++ b/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); } } diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index d8477840af..d61519e697 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/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); + } } /// diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs index 3ae6c8c30e..4f6af0a41b 100644 --- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs +++ b/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) { } diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index 5aa497861d..148916932f 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/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.StyledProperty 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 diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index ba7191d7a6..ae4c927ae2 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -206,14 +206,13 @@ namespace Avalonia.Media /// /// The foreground brush. /// The glyph run. - /// The baseline origin of the glyph run. - public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin) + public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun) { Contract.Requires(glyphRun != null); if (foreground != null) { - PlatformImpl.DrawGlyphRun(foreground, glyphRun, baselineOrigin); + PlatformImpl.DrawGlyphRun(foreground, glyphRun); } } diff --git a/src/Avalonia.Visuals/Media/GlyphRun.cs b/src/Avalonia.Visuals/Media/GlyphRun.cs index da3a1f721c..14ab083b4f 100644 --- a/src/Avalonia.Visuals/Media/GlyphRun.cs +++ b/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 _glyphIndices; private ReadOnlySlice _glyphAdvances; @@ -89,6 +90,20 @@ namespace Avalonia.Media set => Set(ref _fontRenderingEmSize, value); } + /// + /// Gets or sets the baseline origin of the. + /// + public Point BaselineOrigin + { + get + { + _baselineOrigin ??= CalculateBaselineOrigin(); + + return _baselineOrigin.Value; + } + set => Set(ref _baselineOrigin, value); + } + /// /// Gets or sets an array of values that represent the glyph indices in the rendering physical font. /// @@ -156,16 +171,13 @@ namespace Avalonia.Media /// /// Gets or sets the conservative bounding box of the . /// - 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 } /// - /// Calculates the bounds of the . + /// Calculates the default baseline origin of the . + /// + /// The baseline origin. + private Point CalculateBaselineOrigin() + { + return new Point(0, -GlyphTypeface.Ascent * Scale); + } + + /// + /// Calculates the size of the . /// /// /// The calculated bounds. /// - 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(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(); _glyphRunImpl = platformRenderInterface.CreateGlyphRun(this, out var width); var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale; + + _size = new Size(width, height); } void IDisposable.Dispose() diff --git a/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs b/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs index d0ea113a6f..7e0d5c3c81 100644 --- a/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs +++ b/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs @@ -8,9 +8,6 @@ public static readonly StyledProperty GlyphRunProperty = AvaloniaProperty.Register(nameof(GlyphRun)); - public static readonly StyledProperty BaselineOriginProperty = - AvaloniaProperty.Register(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; } } } diff --git a/src/Avalonia.Visuals/Media/TextDecoration.cs b/src/Avalonia.Visuals/Media/TextDecoration.cs index 681fc5d499..d9b3f664ce 100644 --- a/src/Avalonia.Visuals/Media/TextDecoration.cs +++ b/src/Avalonia.Visuals/Media/TextDecoration.cs @@ -155,8 +155,7 @@ namespace Avalonia.Media /// /// The drawing context. /// The shaped characters that are decorated. - /// The origin. - 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)); } } } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs b/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs index 56790cc0db..338c92f6b1 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs @@ -6,15 +6,14 @@ public abstract class DrawableTextRun : TextRun { /// - /// Gets the bounds. + /// Gets the size. /// - public abstract Rect Bounds { get; } + public abstract Size Size { get; } /// /// Draws the at the given origin. /// /// The drawing context. - /// The origin. - public abstract void Draw(DrawingContext drawingContext, Point origin); + public abstract void Draw(DrawingContext drawingContext); } } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs index 9e67a03f45..09ecc0a026 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs @@ -26,7 +26,7 @@ namespace Avalonia.Media.TextFormatting public override int TextSourceLength { get; } /// - public override Rect Bounds => GlyphRun.Bounds; + public override Size Size => GlyphRun.Size; /// /// Gets the font metrics. @@ -45,7 +45,7 @@ namespace Avalonia.Media.TextFormatting public GlyphRun GlyphRun { get; } /// - 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); } } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs index b116249fd4..3e85f0f6f0 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs +++ b/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; diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs index df1ecb4067..daa8807bf6 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs @@ -115,22 +115,24 @@ namespace Avalonia.Media.TextFormatting /// Draws the text layout. /// /// The drawing context. - /// The origin. - 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); - textLine.Draw(context, new Point(origin.X + offsetX, currentY)); + using (context.PushPostTransform(Matrix.CreateTranslation(offsetX, currentY))) + { + textLine.Draw(context); + } currentY += textLine.LineMetrics.Size.Height; } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs index c052fb8948..8a1efa0611 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs @@ -51,8 +51,7 @@ namespace Avalonia.Media.TextFormatting /// Draws the at the given origin. /// /// The drawing context. - /// The origin. - public abstract void Draw(DrawingContext drawingContext, Point origin); + public abstract void Draw(DrawingContext drawingContext); /// /// Create a collapsed line based on collapsed text properties. diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index 51092cddda..f5e87d097b 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -33,17 +33,18 @@ namespace Avalonia.Media.TextFormatting public override bool HasCollapsed { get; } /// - 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(_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; diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs index 6875cc1c04..c4d7527659 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs +++ b/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) { diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index c87946b3ea..019614ae80 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -84,8 +84,7 @@ namespace Avalonia.Platform /// /// The foreground. /// The glyph run. - /// The baseline origin of the glyph run. - void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin); + void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun); /// /// Creates a new that can be used as a render layer diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index 4a364998fd..cb6b1f59d4 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -204,13 +204,13 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin) + public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun) { var next = NextDrawAs(); 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 diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs index bdf05c4f86..a6dba1bd32 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs +++ b/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 /// The transform. /// The foreground brush. /// The glyph run to draw. - /// The baseline origin of the glyph run. /// Child scenes for drawing visual brushes. public GlyphRunNode( Matrix transform, IBrush foreground, GlyphRun glyphRun, - Point baselineOrigin, IDictionary 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 /// public GlyphRun GlyphRun { get; } - /// - /// Gets the baseline origin. - /// - public Point BaselineOrigin { get; set; } - /// public override IDictionary 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); } /// diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index a155fd863b..98528a128a 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -401,16 +401,16 @@ namespace Avalonia.Skia } /// - 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); } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index e0de40525f..258a51db5a 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -324,13 +324,14 @@ namespace Avalonia.Direct2D1.Media /// The foreground. /// The glyph run. /// - 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); } } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs index bf41381b52..f3e1c37705 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs +++ b/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 _);