diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs index 24e9019084..d567ca3f14 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs @@ -294,7 +294,27 @@ namespace Avalonia.Media.TextFormatting var endX = textLine.GetDistanceFromCharacterHit(nextCharacterHit); - return new Rect(startX, currentY, endX - startX, textLine.Height); + var width = endX - startX; + var adjustedX = startX; + + var lineContentLength = textLine.Length - textLine.NewLineLength; + + if (lineContentLength > 0) + { + if (textPosition == textLine.FirstTextSourceIndex && textLine.OverhangLeading < 0 && startX > 0) + { + adjustedX += textLine.OverhangLeading; + width -= textLine.OverhangLeading; + } + + var lastCharacterPosition = textLine.FirstTextSourceIndex + lineContentLength - 1; + if (textPosition >= lastCharacterPosition && textLine.OverhangTrailing < 0) + { + width -= textLine.OverhangTrailing; + } + } + + return new Rect(adjustedX, currentY, width, textLine.Height); } return new Rect(); diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index 12ae974c26..02f7252450 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -1328,7 +1328,7 @@ namespace Avalonia.Media.TextFormatting } } - var inkBounds = new Rect(); + Rect? inkBounds = null; for (var index = 0; index < _textRuns.Length; index++) { @@ -1342,7 +1342,14 @@ namespace Avalonia.Media.TextFormatting var runBounds = glyphRun.InkBounds.Translate(new Vector(widthIncludingWhitespace, offsetY)); - inkBounds = inkBounds.Union(runBounds); + if (inkBounds == null) + { + inkBounds = runBounds; + } + else + { + inkBounds = inkBounds.Value.Union(runBounds); + } widthIncludingWhitespace += textRun.Size.Width; @@ -1354,7 +1361,16 @@ namespace Avalonia.Media.TextFormatting //Align the bounds at the common baseline var offsetY = -ascent - drawableTextRun.Baseline; - inkBounds = inkBounds.Union(new Rect(new Point(widthIncludingWhitespace, offsetY), drawableTextRun.Size)); + var drawableBounds = new Rect(new Point(widthIncludingWhitespace, offsetY), drawableTextRun.Size); + + if (inkBounds == null) + { + inkBounds = drawableBounds; + } + else + { + inkBounds = inkBounds.Value.Union(drawableBounds); + } widthIncludingWhitespace += drawableTextRun.Size.Width; @@ -1362,6 +1378,8 @@ namespace Avalonia.Media.TextFormatting } } } + + var finalInkBounds = inkBounds ?? new Rect(); var halfLineGap = lineGap * 0.5; var naturalHeight = descent - ascent + lineGap; @@ -1416,18 +1434,18 @@ namespace Avalonia.Media.TextFormatting } } - var extent = inkBounds.Height; + var extent = finalInkBounds.Height; //The height of overhanging pixels at the bottom - var overhangAfter = inkBounds.Bottom - height + halfLineGap; + var overhangAfter = finalInkBounds.Bottom - height + halfLineGap; //The width of overhanging pixels at the natural alignment point. Positive value means we are inside. - var overhangLeading = inkBounds.Left; + var overhangLeading = finalInkBounds.Left; //The width of overhanging pixels at the end of the natural bounds. Positive value means we are inside. - var overhangTrailing = widthIncludingWhitespace - inkBounds.Right; - var hasOverflowed = MathUtilities.GreaterThan(width, _paragraphWidth); + var overhangTrailing = widthIncludingWhitespace - finalInkBounds.Right; + var hasOverflowed = width > _paragraphWidth; - var start = GetParagraphOffsetX(width, widthIncludingWhitespace); + var start = GetParagraphOffsetX(width, widthIncludingWhitespace, overhangLeading, overhangTrailing); - _inkBounds = inkBounds.Translate(new Vector(start, 0)); + _inkBounds = finalInkBounds.Translate(new Vector(start, 0)); _bounds = new Rect(start, 0, widthIncludingWhitespace, height); @@ -1453,9 +1471,11 @@ namespace Avalonia.Media.TextFormatting /// /// The line width. /// The paragraph width including whitespace. + /// The leading overhang. + /// The trailing overhang. /// The paragraph offset. - private double GetParagraphOffsetX(double width, double widthIncludingTrailingWhitespace) + private double GetParagraphOffsetX(double width, double widthIncludingTrailingWhitespace, double overhangLeading, double overhangTrailing) { if (double.IsPositiveInfinity(_paragraphWidth)) { @@ -1492,6 +1512,7 @@ namespace Avalonia.Media.TextFormatting switch (textAlignment) { case TextAlignment.Center: + { var start = (_paragraphWidth - width) / 2; if (paragraphFlowDirection == FlowDirection.RightToLeft) @@ -1500,8 +1521,12 @@ namespace Avalonia.Media.TextFormatting } return Math.Max(0, start); + } case TextAlignment.Right: - return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace); + { + var overhangAdjustment = Math.Min(0, overhangTrailing); + return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace + overhangAdjustment); + } default: return 0; } diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 05c74b39e5..7d1a21e020 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -370,6 +370,41 @@ namespace Avalonia.Controls.Presenters return textLayout; } + private double GetLineOffsetX(TextLine line, double controlWidth, TextAlignment textAlignment) + { + var lineInkStartOffset = line.OverhangLeading; + var lineTrailingOverhang = -Math.Min(0, line.OverhangTrailing); + var lineLeadingOverhang = -Math.Min(0, line.OverhangLeading); + var lineInkWidth = line.WidthIncludingTrailingWhitespace + lineLeadingOverhang + lineTrailingOverhang; + + switch (textAlignment) + { + case TextAlignment.Center: + return (controlWidth - lineInkWidth) / 2 - lineInkStartOffset - line.Start; + + case TextAlignment.Right: + return controlWidth - line.WidthIncludingTrailingWhitespace - lineTrailingOverhang - line.Start; + + default: // Left, Justify + return -lineInkStartOffset - line.Start; + } + } + + private TextAlignment GetResolvedTextAlignment() + { + var textAlignment = TextAlignment; + var flowDirection = FlowDirection; + + if (textAlignment == TextAlignment.Start) + return flowDirection == FlowDirection.LeftToRight ? TextAlignment.Left : TextAlignment.Right; + else if (textAlignment == TextAlignment.End) + return flowDirection == FlowDirection.RightToLeft ? TextAlignment.Left : TextAlignment.Right; + else if (textAlignment == TextAlignment.DetectFromContent) + return TextAlignment.Left; + + return textAlignment; + } + /// /// Renders the to a drawing context. /// @@ -383,8 +418,12 @@ namespace Avalonia.Controls.Presenters context.FillRectangle(background, new Rect(Bounds.Size)); } + if (TextLayout.TextLines.Count == 0) + { + return; + } + var top = 0d; - var left = 0.0; var textHeight = TextLayout.Height; @@ -402,7 +441,17 @@ namespace Avalonia.Controls.Presenters } } - TextLayout.Draw(context, new Point(left, top)); + var controlWidth = Bounds.Width; + var textAlignment = GetResolvedTextAlignment(); + + var currentY = top; + + foreach (var line in TextLayout.TextLines) + { + var offsetX = GetLineOffsetX(line, controlWidth, textAlignment); + line.Draw(context, new Point(offsetX, currentY)); + currentY += line.Height; + } } public sealed override void Render(DrawingContext context) @@ -417,10 +466,35 @@ namespace Avalonia.Controls.Presenters var length = Math.Max(selectionStart, selectionEnd) - start; var rects = TextLayout.HitTestTextRange(start, length); + + var controlWidth = Bounds.Width; + var textAlignment = GetResolvedTextAlignment(); foreach (var rect in rects) { - context.FillRectangle(selectionBrush, PixelRect.FromRect(rect, 1).ToRect(1)); + var currentY = 0d; + TextLine? targetLine = null; + + foreach (var line in TextLayout.TextLines) + { + if (currentY + line.Height > rect.Y) + { + targetLine = line; + break; + } + currentY += line.Height; + } + + if (targetLine != null) + { + var offsetX = GetLineOffsetX(targetLine, controlWidth, textAlignment); + var transformedRect = rect.WithX(rect.X + offsetX); + context.FillRectangle(selectionBrush, PixelRect.FromRect(transformedRect, 1).ToRect(1)); + } + else + { + context.FillRectangle(selectionBrush, PixelRect.FromRect(rect, 1).ToRect(1)); + } } } @@ -472,11 +546,18 @@ namespace Avalonia.Controls.Presenters var lineIndex = TextLayout.GetLineIndexFromCharacterIndex(caretIndex, _lastCharacterHit.TrailingLength > 0); var textLine = TextLayout.TextLines[lineIndex]; - var x = Math.Floor(_caretBounds.X) + 0.5; + var caretX = Math.Max(0, _caretBounds.X); + + var x = Math.Floor(caretX) + 0.5; var y = Math.Floor(_caretBounds.Y) + 0.5; var b = Math.Ceiling(_caretBounds.Bottom) - 0.5; - if (_caretBounds.X > 0 && _caretBounds.X >= textLine.WidthIncludingTrailingWhitespace) + var controlWidth = Bounds.Width; + var textAlignment = GetResolvedTextAlignment(); + var offsetX = GetLineOffsetX(textLine, controlWidth, textAlignment); + var lineEndX = textLine.WidthIncludingTrailingWhitespace + offsetX + textLine.Start; + + if (caretX > 0 && caretX >= lineEndX) { x -= 1; } @@ -646,8 +727,17 @@ namespace Avalonia.Controls.Presenters InvalidateArrange(); - // The textWidth used here is matching that TextBlock uses to measure the text. - var textWidth = TextLayout.OverhangLeading + TextLayout.WidthIncludingTrailingWhitespace + TextLayout.OverhangTrailing; + var maxLeadingOverhang = 0.0; + var maxTrailingOverhang = 0.0; + + foreach (var line in TextLayout.TextLines) + { + maxLeadingOverhang = Math.Max(maxLeadingOverhang, -Math.Min(0, line.OverhangLeading)); + maxTrailingOverhang = Math.Max(maxTrailingOverhang, -Math.Min(0, line.OverhangTrailing)); + } + + var textWidth = TextLayout.WidthIncludingTrailingWhitespace + maxLeadingOverhang + maxTrailingOverhang; + return new Size(textWidth, TextLayout.Height); } @@ -655,8 +745,16 @@ namespace Avalonia.Controls.Presenters { var finalWidth = finalSize.Width; - var textWidth = TextLayout.OverhangLeading + TextLayout.WidthIncludingTrailingWhitespace + TextLayout.OverhangTrailing; - textWidth = Math.Ceiling(textWidth); + var maxLeadingOverhang = 0.0; + var maxTrailingOverhang = 0.0; + + foreach (var line in TextLayout.TextLines) + { + maxLeadingOverhang = Math.Max(maxLeadingOverhang, -Math.Min(0, line.OverhangLeading)); + maxTrailingOverhang = Math.Max(maxTrailingOverhang, -Math.Min(0, line.OverhangTrailing)); + } + + var textWidth = Math.Ceiling(TextLayout.WidthIncludingTrailingWhitespace + maxLeadingOverhang + maxTrailingOverhang); if (finalSize.Width < textWidth) { @@ -715,7 +813,9 @@ namespace Avalonia.Controls.Presenters public void MoveCaretToPoint(Point point) { - var hit = TextLayout.HitTestPoint(point); + var transformedPoint = TransformPointToTextLayout(point); + + var hit = TextLayout.HitTestPoint(transformedPoint); UpdateCaret(hit.CharacterHit); @@ -723,6 +823,36 @@ namespace Avalonia.Controls.Presenters CaretChanged(); } + + private Point TransformPointToTextLayout(Point point) + { + if (TextLayout.TextLines.Count == 0) + { + return point; + } + + var controlWidth = Bounds.Width; + var textAlignment = GetResolvedTextAlignment(); + + var currentY = 0d; + TextLine? targetLine = null; + + foreach (var line in TextLayout.TextLines) + { + if (currentY + line.Height > point.Y) + { + targetLine = line; + break; + } + currentY += line.Height; + } + + targetLine ??= TextLayout.TextLines[TextLayout.TextLines.Count - 1]; + + var offsetX = GetLineOffsetX(targetLine, controlWidth, textAlignment); + + return new Point(point.X - offsetX, point.Y); + } public void MoveCaretVertical(LogicalDirection direction = LogicalDirection.Forward) { @@ -917,7 +1047,11 @@ namespace Avalonia.Controls.Presenters distanceY += currentLine.Height; } - var caretBounds = new Rect(distanceX, distanceY, 0, textLine.Height); + var controlWidth = Bounds.Width; + var textAlignment = GetResolvedTextAlignment(); + var offsetX = GetLineOffsetX(textLine, controlWidth, textAlignment); + + var caretBounds = new Rect(distanceX + offsetX, distanceY, 0, textLine.Height); if (caretBounds != _caretBounds) { diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index c70d06ae7f..faa7243535 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -628,9 +628,62 @@ namespace Avalonia.Controls RenderTextLayout(context, new Point(padding.Left, top)); } + private double GetLineOffsetX(TextLine line, double controlWidth, TextAlignment textAlignment) + { + var lineInkStartOffset = line.OverhangLeading; + var lineTrailingOverhang = -Math.Min(0, line.OverhangTrailing); + var lineLeadingOverhang = -Math.Min(0, line.OverhangLeading); + var lineInkWidth = line.WidthIncludingTrailingWhitespace + lineLeadingOverhang + lineTrailingOverhang; + + switch (textAlignment) + { + case TextAlignment.Center: + return (controlWidth - lineInkWidth) / 2 - lineInkStartOffset - line.Start; + + case TextAlignment.Right: + return controlWidth - line.WidthIncludingTrailingWhitespace - lineTrailingOverhang - line.Start; + + default: // Left, Justify + return -lineInkStartOffset - line.Start; + } + } + + private TextAlignment GetResolvedTextAlignment() + { + var textAlignment = TextAlignment; + var flowDirection = FlowDirection; + + if (textAlignment == TextAlignment.Start) + return flowDirection == FlowDirection.LeftToRight ? TextAlignment.Left : TextAlignment.Right; + else if (textAlignment == TextAlignment.End) + return flowDirection == FlowDirection.RightToLeft ? TextAlignment.Left : TextAlignment.Right; + else if (textAlignment == TextAlignment.DetectFromContent) + return TextAlignment.Left; + + return textAlignment; + } + protected virtual void RenderTextLayout(DrawingContext context, Point origin) { - TextLayout.Draw(context, origin); + var textLayout = TextLayout; + + if (textLayout.TextLines.Count == 0) + { + return; + } + + var padding = Padding; + var controlWidth = Bounds.Width - padding.Left - padding.Right; + var textAlignment = GetResolvedTextAlignment(); + + var currentY = origin.Y; + + foreach (var line in textLayout.TextLines) + { + var offsetX = GetLineOffsetX(line, controlWidth, textAlignment); + line.Draw(context, new Point(origin.X + offsetX, currentY)); + currentY += line.Height; + } } private bool _clearTextInternal; @@ -748,8 +801,18 @@ namespace Avalonia.Controls //This implicitly recreated the TextLayout with a new constraint if we previously reset it. var textLayout = TextLayout; - // The textWidth used here is matching that TextPresenter uses to measure the text. - return new Size(textLayout.WidthIncludingTrailingWhitespace, textLayout.Height).Inflate(padding); + var maxLeadingOverhang = 0.0; + var maxTrailingOverhang = 0.0; + + foreach (var line in textLayout.TextLines) + { + maxLeadingOverhang = Math.Max(maxLeadingOverhang, -Math.Min(0, line.OverhangLeading)); + maxTrailingOverhang = Math.Max(maxTrailingOverhang, -Math.Min(0, line.OverhangTrailing)); + } + + var totalWidth = textLayout.WidthIncludingTrailingWhitespace + maxLeadingOverhang + maxTrailingOverhang; + + return new Size(totalWidth, textLayout.Height).Inflate(padding); } protected override Size ArrangeOverride(Size finalSize) diff --git a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs index e7f772190d..fefa0d5872 100644 --- a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs +++ b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs @@ -67,7 +67,7 @@ namespace Avalonia.Skia using var font = CreateFont(defaultTextOptions); - var runBounds = new Rect(); + Rect? runBounds = null; var glyphBounds = ArrayPool.Shared.Rent(count); font.GetGlyphWidths(_glyphIndices, null, glyphBounds.AsSpan(0, count)); @@ -79,14 +79,23 @@ namespace Avalonia.Skia var gBounds = glyphBounds[i]; var advance = glyphInfos[i].GlyphAdvance; - runBounds = runBounds.Union(new Rect(currentX + gBounds.Left, gBounds.Top, gBounds.Width, gBounds.Height)); + var glyphRect = new Rect(currentX + gBounds.Left, gBounds.Top, gBounds.Width, gBounds.Height); + + if (runBounds == null) + { + runBounds = glyphRect; + } + else + { + runBounds = runBounds.Value.Union(glyphRect); + } currentX += advance; } ArrayPool.Shared.Return(glyphBounds); BaselineOrigin = baselineOrigin; - Bounds = runBounds.Translate(new Vector(baselineOrigin.X, baselineOrigin.Y)); + Bounds = (runBounds ?? new Rect()).Translate(new Vector(baselineOrigin.X, baselineOrigin.Y)); } public double FontRenderingEmSize { get; } diff --git a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs index d5406c5593..b2e0936dad 100644 --- a/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.RenderTests/Media/TextFormatting/TextLayoutTests.cs @@ -178,7 +178,7 @@ namespace Avalonia.Skia.RenderTests [Theory] [InlineData("x", 0, 200, 200 - 7.20, 0, 7.20, FontSizeHeight)] - [InlineData(stringword, 0, 200, 171.20, 0, 7.20, FontSizeHeight)] + [InlineData(stringword, 0, 200, 170.20, 0, 8.20, FontSizeHeight)] [InlineData(stringword, 3, 200, 200 - 7.20, 0, 7.20, FontSizeHeight)] public void Should_HitTestPosition_RightAlign_Correctly( string input, int index, double widthConstraint, @@ -197,7 +197,7 @@ namespace Avalonia.Skia.RenderTests [Theory] [InlineData("x", 0, 200, 100 - 7.20 / 2, 0, 7.20, FontSizeHeight)] - [InlineData(stringword, 0, 200, 85.6, 0, 7.20, FontSizeHeight)] + [InlineData(stringword, 0, 200, 84.6, 0, 8.20, FontSizeHeight)] [InlineData(stringword, 3, 200, 100 + 7.20, 0, 7.20, FontSizeHeight)] public void Should_HitTestPosition_CenterAlign_Correctly( string input, int index, double widthConstraint, diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 182c633418..9f60d19c20 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs @@ -696,7 +696,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting expectedOffset = 50 - textLine.Width / 2; break; case TextAlignment.Right: - expectedOffset = 100 - textLine.WidthIncludingTrailingWhitespace; + var overhangAdjustment = Math.Min(0, textLine.OverhangTrailing); + expectedOffset = 100 - textLine.WidthIncludingTrailingWhitespace + overhangAdjustment; break; } diff --git a/tests/TestFiles/Skia/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png index 30e2ca8662..6115fd566f 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png and b/tests/TestFiles/Skia/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png index 23267da7df..78b4be7b44 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Account_For_Overhang_Leading_And_Trailing.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png index 7b4541d3f8..f1fedd01f3 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Draw_MultiLineText_WithOverHandLeadingTrailing.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png index ff8f49b60b..f345fc35bb 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Keep_TrailingWhiteSpace.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png index 0d407ba1ee..6be98a4fea 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png index 39f21bd807..e1d2a574c2 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png and b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Blue_Foreground.expected.png b/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Blue_Foreground.expected.png index d2262f7e52..fd82dfb4bc 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Blue_Foreground.expected.png and b/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Blue_Foreground.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Default_Foreground.expected.png b/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Default_Foreground.expected.png index 770ff257b4..2ea296ee0e 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Default_Foreground.expected.png and b/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Default_Foreground.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Red_Foreground.expected.png b/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Red_Foreground.expected.png index 4d2bc5d78b..05ecbea9a2 100644 Binary files a/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Red_Foreground.expected.png and b/tests/TestFiles/Skia/Controls/TextBox/Placeholder_With_Red_Foreground.expected.png differ