From 924139653dacf87cdf71870604797e4aa6b767cb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Jan 2025 12:06:46 +1000 Subject: [PATCH 1/2] Fix newline handling and whitespace trimming --- src/SixLabors.Fonts/GlyphMetrics.cs | 3 +- src/SixLabors.Fonts/TextLayout.cs | 87 +++++++++++++++---- ...thExplicitNewLine__WrappingLength_800_.png | 3 + ...thImplicitNewLine__WrappingLength_800_.png | 3 + ...ncludesAllGlyphs__WrappingLength_1900_.png | 3 + ...=> ShouldInsertExtraLineBreaksA_400-5.png} | 0 ...=> ShouldInsertExtraLineBreaksB_400-6.png} | 0 .../SixLabors.Fonts.Tests/Issues/Issues_27.cs | 2 +- .../SixLabors.Fonts.Tests/Issues/Issues_33.cs | 4 +- .../SixLabors.Fonts.Tests/Issues/Issues_35.cs | 40 +++------ .../SixLabors.Fonts.Tests/Issues/Issues_36.cs | 20 +++-- .../Issues/Issues_400.cs | 4 +- .../Issues/Issues_434.cs | 20 ++--- .../Issues/Issues_441.cs | 43 +++++++++ 14 files changed, 161 insertions(+), 71 deletions(-) create mode 100644 tests/Images/ReferenceOutput/LineWrappingWithExplicitNewLine__WrappingLength_800_.png create mode 100644 tests/Images/ReferenceOutput/LineWrappingWithImplicitNewLine__WrappingLength_800_.png create mode 100644 tests/Images/ReferenceOutput/RenderingTextIncludesAllGlyphs__WrappingLength_1900_.png rename tests/Images/ReferenceOutput/{ShouldInsertExtraLineBreaksA_400-4.png => ShouldInsertExtraLineBreaksA_400-5.png} (100%) rename tests/Images/ReferenceOutput/{ShouldInsertExtraLineBreaksB_400-4.png => ShouldInsertExtraLineBreaksB_400-6.png} (100%) create mode 100644 tests/SixLabors.Fonts.Tests/Issues/Issues_441.cs diff --git a/src/SixLabors.Fonts/GlyphMetrics.cs b/src/SixLabors.Fonts/GlyphMetrics.cs index 86baf52b..58219348 100644 --- a/src/SixLabors.Fonts/GlyphMetrics.cs +++ b/src/SixLabors.Fonts/GlyphMetrics.cs @@ -401,7 +401,8 @@ void SetDecoration(TextDecorations decorations, float thickness, float position) /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] protected internal static bool ShouldSkipGlyphRendering(CodePoint codePoint) - => UnicodeUtility.IsDefaultIgnorableCodePoint((uint)codePoint.Value) && !UnicodeUtility.ShouldRenderWhiteSpaceOnly(codePoint); + => CodePoint.IsNewLine(codePoint) || + (UnicodeUtility.IsDefaultIgnorableCodePoint((uint)codePoint.Value) && !UnicodeUtility.ShouldRenderWhiteSpaceOnly(codePoint)); /// /// Returns the size to render/measure the glyph based on the given size and resolution in px units. diff --git a/src/SixLabors.Fonts/TextLayout.cs b/src/SixLabors.Fonts/TextLayout.cs index fdd1402d..c32930c5 100644 --- a/src/SixLabors.Fonts/TextLayout.cs +++ b/src/SixLabors.Fonts/TextLayout.cs @@ -391,12 +391,23 @@ private static IEnumerable LayoutLineHorizontal( TextLine.GlyphLayoutData data = textLine[i]; if (data.IsNewLine) { + glyphs.Add(new GlyphLayout( + new Glyph(data.Metrics[0], data.PointSize), + boxLocation, + penLocation, + Vector2.Zero, + data.ScaledAdvance, + yLineAdvance, + GlyphLayoutMode.Horizontal, + true, + data.GraphemeIndex, + data.StringIndex)); + penLocation.X = originX; penLocation.Y += yLineAdvance; - boxLocation.X = originX; boxLocation.Y += advanceY; - continue; + goto end; } int j = 0; @@ -429,6 +440,7 @@ private static IEnumerable LayoutLineHorizontal( boxLocation.Y += advanceY; } + end: return glyphs; } @@ -524,12 +536,23 @@ private static IEnumerable LayoutLineVertical( TextLine.GlyphLayoutData data = textLine[i]; if (data.IsNewLine) { + glyphs.Add(new GlyphLayout( + new Glyph(data.Metrics[0], data.PointSize), + boxLocation, + penLocation, + Vector2.Zero, + xLineAdvance, + data.ScaledAdvance, + GlyphLayoutMode.Vertical, + true, + data.GraphemeIndex, + data.StringIndex)); + boxLocation.X += advanceX; boxLocation.Y = originY; - penLocation.X += xLineAdvance; penLocation.Y = originY; - continue; + goto end; } int j = 0; @@ -576,6 +599,7 @@ private static IEnumerable LayoutLineVertical( penLocation.X += xLineAdvance; } + end: return glyphs; } @@ -671,12 +695,23 @@ private static IEnumerable LayoutLineVerticalMixed( TextLine.GlyphLayoutData data = textLine[i]; if (data.IsNewLine) { + glyphs.Add(new GlyphLayout( + new Glyph(data.Metrics[0], data.PointSize), + boxLocation, + penLocation, + Vector2.Zero, + xLineAdvance, + data.ScaledAdvance, + GlyphLayoutMode.Vertical, + true, + data.GraphemeIndex, + data.StringIndex)); + boxLocation.X += advanceX; boxLocation.Y = originY; - penLocation.X += xLineAdvance; penLocation.Y = originY; - continue; + goto end; } if (data.IsTransformed) @@ -752,6 +787,7 @@ private static IEnumerable LayoutLineVerticalMixed( penLocation.X += xLineAdvance; } + end: return glyphs; } @@ -1170,10 +1206,30 @@ VerticalOrientationType.Rotate or { // Mandatory line break at index. TextLine remaining = textLine.SplitAt(i); - textLines.Add(textLine.Finalize(options)); - textLine = remaining; - i = -1; - lineAdvance = 0; + + if (shouldWrap && textLine.ScaledLineAdvance - glyph.ScaledAdvance > wrappingLength) + { + // We've overshot the wrapping length so we need to split the line + // at the previous break and add both lines. + TextLine overflow = textLine.SplitAt(lastLineBreak, keepAll); + if (overflow != textLine) + { + textLines.Add(textLine.Finalize(options)); + textLine = overflow; + } + + textLines.Add(textLine.Finalize(options)); + textLine = remaining; + i = -1; + lineAdvance = 0; + } + else + { + textLines.Add(textLine.Finalize(options)); + textLine = remaining; + i = -1; + lineAdvance = 0; + } } else if (shouldWrap) { @@ -1201,7 +1257,7 @@ VerticalOrientationType.Rotate or { // If the current break is a space, and the line minus the space // is less than the wrapping length, we can break using the current break. - float previousAdvance = lineAdvance - (float)glyph.ScaledAdvance; + float previousAdvance = lineAdvance - glyph.ScaledAdvance; TextLine.GlyphLayoutData lastGlyph = textLine[i - 1]; if (CodePoint.IsWhiteSpace(lastGlyph.CodePoint)) { @@ -1463,8 +1519,9 @@ public TextLine SplitAt(LineBreak lineBreak, bool keepAll) private void TrimTrailingWhitespace() { - int index = this.data.Count; - while (index > 0) + int count = this.data.Count; + int index = count; + while (index > 1) { // Trim trailing breaking whitespace. CodePoint point = this.data[index - 1].CodePoint; @@ -1476,9 +1533,9 @@ private void TrimTrailingWhitespace() index--; } - if (index < this.data.Count && index != 0) + if (index < count) { - this.data.RemoveRange(index, this.data.Count - index); + this.data.RemoveRange(index, count - index); } } diff --git a/tests/Images/ReferenceOutput/LineWrappingWithExplicitNewLine__WrappingLength_800_.png b/tests/Images/ReferenceOutput/LineWrappingWithExplicitNewLine__WrappingLength_800_.png new file mode 100644 index 00000000..ed2adad0 --- /dev/null +++ b/tests/Images/ReferenceOutput/LineWrappingWithExplicitNewLine__WrappingLength_800_.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b4b11a402255b4dca480bece6991e6ec4514e08c29fdad0b29aca09f9a274e8 +size 16832 diff --git a/tests/Images/ReferenceOutput/LineWrappingWithImplicitNewLine__WrappingLength_800_.png b/tests/Images/ReferenceOutput/LineWrappingWithImplicitNewLine__WrappingLength_800_.png new file mode 100644 index 00000000..d167a331 --- /dev/null +++ b/tests/Images/ReferenceOutput/LineWrappingWithImplicitNewLine__WrappingLength_800_.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7385a22475af5810017247faa02cea7cf406b8b14440f82c6972d04020c154d6 +size 15927 diff --git a/tests/Images/ReferenceOutput/RenderingTextIncludesAllGlyphs__WrappingLength_1900_.png b/tests/Images/ReferenceOutput/RenderingTextIncludesAllGlyphs__WrappingLength_1900_.png new file mode 100644 index 00000000..afea7655 --- /dev/null +++ b/tests/Images/ReferenceOutput/RenderingTextIncludesAllGlyphs__WrappingLength_1900_.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09759e0fda60ef494d81a8c8abefce73c2f896154e29c1d3e28c419b2597fc48 +size 23678 diff --git a/tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksA_400-4.png b/tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksA_400-5.png similarity index 100% rename from tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksA_400-4.png rename to tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksA_400-5.png diff --git a/tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksB_400-4.png b/tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksB_400-6.png similarity index 100% rename from tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksB_400-4.png rename to tests/Images/ReferenceOutput/ShouldInsertExtraLineBreaksB_400-6.png diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_27.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_27.cs index 71dcbc94..bf52e238 100644 --- a/tests/SixLabors.Fonts.Tests/Issues/Issues_27.cs +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_27.cs @@ -12,7 +12,7 @@ public void ThrowsMeasuringWhitespace() Font font = new FontCollection().Add(TestFonts.WendyOneFile).CreateFont(12); FontRectangle size = TextMeasurer.MeasureBounds(" ", new TextOptions(new Font(font, 30))); - Assert.Equal(60, size.Width, 1F); + Assert.Equal(6, size.Width, 1F); Assert.Equal(0, size.Height, 1F); } } diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_33.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_33.cs index 6e7f5d14..8b2db2c7 100644 --- a/tests/SixLabors.Fonts.Tests/Issues/Issues_33.cs +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_33.cs @@ -9,8 +9,8 @@ namespace SixLabors.Fonts.Tests.Issues; public class Issues_33 { [Theory] - [InlineData("\naaaabbbbccccddddeeee\n\t\t\t3 tabs\n\t\t\t\t\t5 tabs", 580, 70)] // newlines aren't directly measured but it is used for offsetting - [InlineData("\n\tHelloworld", 310, 10)] + [InlineData("\naaaabbbbccccddddeeee\n\t\t\t3 tabs\n\t\t\t\t\t5 tabs", 580, 120)] + [InlineData("\n\tHelloworld", 310, 60)] [InlineData("\tHelloworld", 310, 10)] [InlineData(" Helloworld", 340, 10)] [InlineData("Hell owor ld\t", 340, 10)] diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_35.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_35.cs index 268ba043..1a8eb029 100644 --- a/tests/SixLabors.Fonts.Tests/Issues/Issues_35.cs +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_35.cs @@ -12,20 +12,10 @@ public class Issues_35 public void RenderingTabAtStartOrLineTooShort() { Font font = CreateFont("\t x"); - FontRectangle xWidth = TextMeasurer.MeasureBounds("x", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWithXWidth = TextMeasurer.MeasureBounds("\tx", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - - Assert.Equal(tabWidth.Width + xWidth.Width, tabWithXWidth.Width, 2F); - } - - [Fact] - public void Rendering2TabsAtStartOfLineTooShort() - { - Font font = CreateFont("\t x"); - FontRectangle xWidth = TextMeasurer.MeasureBounds("x", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t\t", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWithXWidth = TextMeasurer.MeasureBounds("\t\tx", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); + TextOptions options = new(font) { Dpi = font.FontMetrics.ScaleFactor }; + FontRectangle xWidth = TextMeasurer.MeasureBounds("x", options); + FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t", options); + FontRectangle tabWithXWidth = TextMeasurer.MeasureBounds("\tx", options); Assert.Equal(tabWidth.Width + xWidth.Width, tabWithXWidth.Width, 2F); } @@ -34,27 +24,17 @@ public void Rendering2TabsAtStartOfLineTooShort() public void TwoTabsAreDoubleWidthOfOneTab() { Font font = CreateFont("\t x"); - FontRectangle xWidth = TextMeasurer.MeasureBounds("x", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle twoTabWidth = TextMeasurer.MeasureBounds("\t\t", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - - Assert.Equal(twoTabWidth.Width, tabWidth.Width * 2, 2F); - } - - [Fact] - public void TwoTabsAreDoubleWidthOfOneTabMinusXWidth() - { - Font font = CreateFont("\t x"); - FontRectangle xWidth = TextMeasurer.MeasureBounds("x", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWidth = TextMeasurer.MeasureBounds("\tx", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle twoTabWidth = TextMeasurer.MeasureBounds("\t\tx", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); + TextOptions options = new(font) { Dpi = font.FontMetrics.ScaleFactor }; + FontRectangle xWidth = TextMeasurer.MeasureBounds("x", options); + FontRectangle tabWithXWidth = TextMeasurer.MeasureBounds("\tx", options); + FontRectangle tabTabWithXWidth = TextMeasurer.MeasureBounds("\t\tx", options); - Assert.Equal(twoTabWidth.Width - xWidth.Width, (tabWidth.Width - xWidth.Width) * 2, 2F); + Assert.Equal(tabTabWithXWidth.Width - xWidth.Width, 2 * (tabWithXWidth.Width - xWidth.Width), 2F); } public static Font CreateFont(string text) { - var fc = (IFontMetricsCollection)new FontCollection(); + IFontMetricsCollection fc = new FontCollection(); Font d = fc.AddMetrics(new FakeFontInstance(text), CultureInfo.InvariantCulture).CreateFont(12); return new Font(d, 1F); } diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_36.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_36.cs index ede609a9..9b849369 100644 --- a/tests/SixLabors.Fonts.Tests/Issues/Issues_36.cs +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_36.cs @@ -14,15 +14,16 @@ public class Issues_36 [InlineData(3)] [InlineData(4)] [InlineData(5)] - public void TextWidthForTabOnlyTextShouldBeSingleTabWidthMultipliedByTabCount(int tabCount) + public void TextWidthForTabOnlyTextShouldBeSingleTabWidth(int tabCount) { - Font font = CreateFont("\t x"); + Font font = CreateFont("\t"); + TextOptions options = new(font) { Dpi = font.FontMetrics.ScaleFactor }; - FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); + FontRectangle tabWidth = TextMeasurer.MeasureBounds("\t", options); string tabString = string.Empty.PadRight(tabCount, '\t'); - FontRectangle tabCountWidth = TextMeasurer.MeasureBounds(tabString, new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); + FontRectangle tabCountWidth = TextMeasurer.MeasureBounds(tabString, options); - Assert.Equal(tabWidth.Width * tabCount, tabCountWidth.Width, 2F); + Assert.Equal(tabWidth.Width, tabCountWidth.Width, 2F); } [Theory] @@ -35,10 +36,11 @@ public void TextWidthForTabOnlyTextShouldBeSingleTabWidthMultipliedByTabCountMin { Font font = CreateFont("\t x"); - FontRectangle xWidth = TextMeasurer.MeasureBounds("x", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); - FontRectangle tabWidth = TextMeasurer.MeasureBounds("\tx", new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); + TextOptions options = new(font) { Dpi = font.FontMetrics.ScaleFactor }; + FontRectangle xWidth = TextMeasurer.MeasureBounds("x", options); + FontRectangle tabWidth = TextMeasurer.MeasureBounds("\tx", options); string tabString = "x".PadLeft(tabCount + 1, '\t'); - FontRectangle tabCountWidth = TextMeasurer.MeasureBounds(tabString, new TextOptions(font) { Dpi = font.FontMetrics.ScaleFactor }); + FontRectangle tabCountWidth = TextMeasurer.MeasureBounds(tabString, options); float singleTabWidth = tabWidth.Width - xWidth.Width; float finalTabWidth = tabCountWidth.Width - xWidth.Width; @@ -47,7 +49,7 @@ public void TextWidthForTabOnlyTextShouldBeSingleTabWidthMultipliedByTabCountMin public static Font CreateFont(string text) { - var fc = (IFontMetricsCollection)new FontCollection(); + IFontMetricsCollection fc = new FontCollection(); Font d = fc.AddMetrics(new FakeFontInstance(text), CultureInfo.InvariantCulture).CreateFont(12); return new Font(d, 1F); } diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_400.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_400.cs index fd9ec3cf..60d5ca06 100644 --- a/tests/SixLabors.Fonts.Tests/Issues/Issues_400.cs +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_400.cs @@ -22,8 +22,10 @@ public void RenderingTextIncludesAllGlyphs() .AppendLine(" NEWS_CATEGORY=EWF&NEWS_HASH=4b298ff9277ef9fdf515356be95ea3caf57cd36&OFFSET=0&SEARCH_VALUE=CA88105E1088&ID_NEWS") .Append(" "); + TextLayoutTestUtilities.TestLayout(stringBuilder.ToString(), options); + int lineCount = TextMeasurer.CountLines(stringBuilder.ToString(), options); - Assert.Equal(2, lineCount); + Assert.Equal(4, lineCount); #endif } } diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_434.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_434.cs index 01cc6bee..6475667d 100644 --- a/tests/SixLabors.Fonts.Tests/Issues/Issues_434.cs +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_434.cs @@ -8,7 +8,7 @@ namespace SixLabors.Fonts.Tests.Issues; public class Issues_434 { [Theory] - [InlineData("- Lorem ipsullll\n\ndolor sit amet\n-consectetur elit", 4)] + [InlineData("- Lorem ipsullll\n\ndolor sit amet\n-consectetur elit", 5)] public void ShouldInsertExtraLineBreaksA(string text, int expectedLineCount) { if (SystemFonts.TryGet("Arial", out FontFamily family)) @@ -20,20 +20,18 @@ public void ShouldInsertExtraLineBreaksA(string text, int expectedLineCount) WrappingLength = 400, }; - // Line count includes rendered lines only. - // Line breaks cause offsetting of subsequent lines. + TextLayoutTestUtilities.TestLayout(text, options, properties: expectedLineCount); + int lineCount = TextMeasurer.CountLines(text, options); Assert.Equal(expectedLineCount, lineCount); IReadOnlyList layout = TextLayout.GenerateLayout(text, options); - Assert.Equal(46, layout.Count); - - TextLayoutTestUtilities.TestLayout(text, options, properties: expectedLineCount); + Assert.Equal(47, layout.Count); } } [Theory] - [InlineData("- Lorem ipsullll\n\n\ndolor sit amet\n-consectetur elit", 4)] + [InlineData("- Lorem ipsullll\n\n\ndolor sit amet\n-consectetur elit", 6)] public void ShouldInsertExtraLineBreaksB(string text, int expectedLineCount) { if (SystemFonts.TryGet("Arial", out FontFamily family)) @@ -45,15 +43,13 @@ public void ShouldInsertExtraLineBreaksB(string text, int expectedLineCount) WrappingLength = 400, }; - // Line count includes rendered lines only. - // Line breaks cause offsetting of subsequent lines. + TextLayoutTestUtilities.TestLayout(text, options, properties: expectedLineCount); + int lineCount = TextMeasurer.CountLines(text, options); Assert.Equal(expectedLineCount, lineCount); IReadOnlyList layout = TextLayout.GenerateLayout(text, options); - Assert.Equal(46, layout.Count); - - TextLayoutTestUtilities.TestLayout(text, options, properties: expectedLineCount); + Assert.Equal(48, layout.Count); } } } diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_441.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_441.cs new file mode 100644 index 00000000..39567162 --- /dev/null +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_441.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.Fonts.Tests.Issues; + +public class Issues_441 +{ + [Fact] + public void LineWrappingWithExplicitNewLine() + { + if (SystemFonts.TryGet("Arial", out FontFamily family)) + { + Font font = family.CreateFont(80); + + TextLayoutTestUtilities.TestLayout( + "What connects the following:\nx", + new TextOptions(font) + { + Origin = new Vector2(50, 20), + WrappingLength = 800 + }); + } + } + + [Fact] + public void LineWrappingWithImplicitNewLine() + { + if (SystemFonts.TryGet("Arial", out FontFamily family)) + { + Font font = family.CreateFont(80); + + TextLayoutTestUtilities.TestLayout( + "What connects the following: x", + new TextOptions(font) + { + Origin = new Vector2(50, 20), + WrappingLength = 800 + }); + } + } +} From d6c5c87ae19501c33de33ad00a889a58e35fcfdd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 20 Jan 2025 22:16:15 +1000 Subject: [PATCH 2/2] return > goto --- src/SixLabors.Fonts/TextLayout.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/SixLabors.Fonts/TextLayout.cs b/src/SixLabors.Fonts/TextLayout.cs index c32930c5..24f26901 100644 --- a/src/SixLabors.Fonts/TextLayout.cs +++ b/src/SixLabors.Fonts/TextLayout.cs @@ -407,7 +407,7 @@ private static IEnumerable LayoutLineHorizontal( penLocation.Y += yLineAdvance; boxLocation.X = originX; boxLocation.Y += advanceY; - goto end; + return glyphs; } int j = 0; @@ -440,7 +440,6 @@ private static IEnumerable LayoutLineHorizontal( boxLocation.Y += advanceY; } - end: return glyphs; } @@ -552,7 +551,7 @@ private static IEnumerable LayoutLineVertical( boxLocation.Y = originY; penLocation.X += xLineAdvance; penLocation.Y = originY; - goto end; + return glyphs; } int j = 0; @@ -599,7 +598,6 @@ private static IEnumerable LayoutLineVertical( penLocation.X += xLineAdvance; } - end: return glyphs; } @@ -711,7 +709,7 @@ private static IEnumerable LayoutLineVerticalMixed( boxLocation.Y = originY; penLocation.X += xLineAdvance; penLocation.Y = originY; - goto end; + return glyphs; } if (data.IsTransformed) @@ -787,7 +785,6 @@ private static IEnumerable LayoutLineVerticalMixed( penLocation.X += xLineAdvance; } - end: return glyphs; }