From 83d24b7cef4091b06d3a38e9e1da6e3705112c55 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Feb 2024 20:44:22 +1000 Subject: [PATCH] Ensure we never add empty text lines --- src/SixLabors.Fonts/TextLayout.cs | 8 +- .../Issues/Issues_383.cs | 94 +++++++++++++++++++ 2 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 tests/SixLabors.Fonts.Tests/Issues/Issues_383.cs diff --git a/src/SixLabors.Fonts/TextLayout.cs b/src/SixLabors.Fonts/TextLayout.cs index c0c41207..84d4af37 100644 --- a/src/SixLabors.Fonts/TextLayout.cs +++ b/src/SixLabors.Fonts/TextLayout.cs @@ -1066,7 +1066,7 @@ private static TextBox BreakLines( else if (shouldWrap && lineAdvance + glyphAdvance >= wrappingLength) { // Forced wordbreak - if (breakAll) + if (breakAll && textLine.Count > 0) { textLines.Add(textLine.Finalize()); glyphCount += textLine.Count; @@ -1086,7 +1086,7 @@ private static TextBox BreakLines( lineAdvance = split.ScaledLineAdvance; } } - else + else if (textLine.Count > 0) { textLines.Add(textLine.Finalize()); glyphCount += textLine.Count; @@ -1123,7 +1123,7 @@ private static TextBox BreakLines( textLine = split; lineAdvance = split.ScaledLineAdvance; } - else if (breakWord) + else if (breakWord && textLine.Count > 0) { textLines.Add(textLine.Finalize()); glyphCount += textLine.Count; @@ -1131,7 +1131,7 @@ private static TextBox BreakLines( lineAdvance = 0; } } - else if (breakWord) + else if (breakWord && textLine.Count > 0) { textLines.Add(textLine.Finalize()); glyphCount += textLine.Count; diff --git a/tests/SixLabors.Fonts.Tests/Issues/Issues_383.cs b/tests/SixLabors.Fonts.Tests/Issues/Issues_383.cs new file mode 100644 index 00000000..73ff6e82 --- /dev/null +++ b/tests/SixLabors.Fonts.Tests/Issues/Issues_383.cs @@ -0,0 +1,94 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +#if OS_WINDOWS +using System.Numerics; + +namespace SixLabors.Fonts.Tests.Issues; + +public class Issues_383 +{ + [Fact] + public void CanBreakLinesWithShortWrappingLength() + { + FontFamily fontFamily = SystemFonts.Get("Yu Gothic"); + Font font = fontFamily.CreateFont(20.0F); + + TextOptions textOption = new(font) + { + WrappingLength = 10.0F, + WordBreaking = WordBreaking.BreakAll + }; + + // OK + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "i", textOption); + + // OK + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "v", textOption); + + // raise ArgumentOutOfRangeException + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "a", textOption); + + textOption.WrappingLength = 9.0F; + + // OK + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "i", textOption); + + // raise ArgumentOutOfRangeException + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "v", textOption); + + // OK + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "i\r\nv", textOption); + + // raise ArgumentOutOfRangeException + TextRenderer.RenderTextTo(new DummyGlyphRenderer(), "v\r\ni", textOption); + } +} + +internal class DummyGlyphRenderer : IGlyphRenderer +{ + public void BeginFigure() + { + } + + public bool BeginGlyph(in FontRectangle bounds, in GlyphRendererParameters parameters) => true; + + public void BeginText(in FontRectangle bounds) + { + } + + public void CubicBezierTo(Vector2 secondControlPoint, Vector2 thirdControlPoint, Vector2 point) + { + } + + public TextDecorations EnabledDecorations() => TextDecorations.None; + + public void EndFigure() + { + } + + public void EndGlyph() + { + } + + public void EndText() + { + } + + public void LineTo(Vector2 point) + { + } + + public void MoveTo(Vector2 point) + { + } + + public void QuadraticBezierTo(Vector2 secondControlPoint, Vector2 point) + { + } + + public void SetDecoration(TextDecorations textDecorations, Vector2 start, Vector2 end, float thickness) + { + } +} +#endif