Skip to content

Commit 24871a8

Browse files
Merge pull request #440 from SixLabors/js/additional-linebreak-fixes
Fix calculation of wrapping advance
2 parents 6de8c5c + 371e95a commit 24871a8

17 files changed

+101
-67
lines changed

src/SixLabors.Fonts/TextLayout.cs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,8 @@ private static TextBox BreakLines(
894894
LayoutMode layoutMode)
895895
{
896896
bool shouldWrap = options.WrappingLength > 0;
897+
898+
// Wrapping length is always provided in pixels. Convert to inches for comparison.
897899
float wrappingLength = shouldWrap ? options.WrappingLength / options.Dpi : float.MaxValue;
898900
bool breakAll = options.WordBreaking == WordBreaking.BreakAll;
899901
bool keepAll = options.WordBreaking == WordBreaking.KeepAll;
@@ -904,7 +906,6 @@ private static TextBox BreakLines(
904906

905907
int graphemeIndex;
906908
int codePointIndex = 0;
907-
float lineAdvance = 0;
908909
List<TextLine> textLines = new();
909910
TextLine textLine = new();
910911
int stringIndex = 0;
@@ -1073,7 +1074,7 @@ VerticalOrientationType.Rotate or
10731074
}
10741075
}
10751076

1076-
// Now scale the advance.
1077+
// Now scale the advance. We use inches for comparison.
10771078
if (isHorizontalLayout || shouldRotate)
10781079
{
10791080
float scaleAX = pointSize / glyph.ScaleFactor.X;
@@ -1115,7 +1116,6 @@ VerticalOrientationType.Rotate or
11151116
descender -= delta;
11161117

11171118
// Add our metrics to the line.
1118-
lineAdvance += decomposedAdvance;
11191119
textLine.Add(
11201120
isDecomposed ? new GlyphMetrics[] { metric } : metrics,
11211121
pointSize,
@@ -1153,58 +1153,60 @@ VerticalOrientationType.Rotate or
11531153
int maxLineBreakIndex = lineBreaks.Count - 1;
11541154
LineBreak lastLineBreak = lineBreaks[lineBreakIndex];
11551155
LineBreak currentLineBreak = lineBreaks[lineBreakIndex];
1156+
float lineAdvance = 0;
11561157

1157-
lineAdvance = 0;
11581158
for (int i = 0; i < textLine.Count; i++)
11591159
{
11601160
int max = textLine.Count - 1;
11611161
TextLine.GlyphLayoutData glyph = textLine[i];
11621162
codePointIndex = glyph.CodePointIndex;
11631163
int graphemeCodePointIndex = glyph.GraphemeCodePointIndex;
1164-
float glyphAdvance = glyph.ScaledAdvance;
1165-
lineAdvance += glyphAdvance;
11661164

11671165
if (graphemeCodePointIndex == 0 && textLine.Count > 0)
11681166
{
1167+
lineAdvance += glyph.ScaledAdvance;
1168+
11691169
if (codePointIndex == currentLineBreak.PositionWrap && currentLineBreak.Required)
11701170
{
11711171
// Mandatory line break at index.
11721172
TextLine remaining = textLine.SplitAt(i);
11731173
textLines.Add(textLine.Finalize(options));
11741174
textLine = remaining;
1175-
i = 0;
1175+
i = -1;
11761176
lineAdvance = 0;
11771177
}
11781178
else if (shouldWrap)
11791179
{
1180-
float currentAdvance = lineAdvance + glyphAdvance;
1181-
if (currentAdvance >= wrappingLength)
1180+
if (lineAdvance >= wrappingLength)
11821181
{
11831182
if (breakAll)
11841183
{
1185-
// Insert a forced break at this index.
1184+
// Insert a forced break.
11861185
TextLine remaining = textLine.SplitAt(i);
1187-
textLines.Add(textLine.Finalize(options));
1188-
textLine = remaining;
1189-
i = 0;
1190-
lineAdvance = 0;
1186+
if (remaining != textLine)
1187+
{
1188+
textLines.Add(textLine.Finalize(options));
1189+
textLine = remaining;
1190+
i = -1;
1191+
lineAdvance = 0;
1192+
}
11911193
}
11921194
else if (codePointIndex == currentLineBreak.PositionWrap || i == max)
11931195
{
1194-
LineBreak lineBreak = currentAdvance == wrappingLength
1196+
LineBreak lineBreak = lineAdvance == wrappingLength
11951197
? currentLineBreak
11961198
: lastLineBreak;
11971199

11981200
if (i > 0)
11991201
{
12001202
// If the current break is a space, and the line minus the space
12011203
// is less than the wrapping length, we can break using the current break.
1202-
float positionAdvance = lineAdvance;
1204+
float previousAdvance = lineAdvance - (float)glyph.ScaledAdvance;
12031205
TextLine.GlyphLayoutData lastGlyph = textLine[i - 1];
12041206
if (CodePoint.IsWhiteSpace(lastGlyph.CodePoint))
12051207
{
1206-
positionAdvance -= lastGlyph.ScaledAdvance;
1207-
if (positionAdvance <= wrappingLength)
1208+
previousAdvance -= lastGlyph.ScaledAdvance;
1209+
if (previousAdvance <= wrappingLength)
12081210
{
12091211
lineBreak = currentLineBreak;
12101212
}
@@ -1220,7 +1222,7 @@ VerticalOrientationType.Rotate or
12201222
{
12211223
if (breakWord)
12221224
{
1223-
// If the line is too long, insert a forced line break.
1225+
// If the line is too long, insert a forced break.
12241226
if (textLine.ScaledLineAdvance > wrappingLength)
12251227
{
12261228
TextLine overflow = textLine.SplitAt(wrappingLength);
@@ -1233,7 +1235,7 @@ VerticalOrientationType.Rotate or
12331235

12341236
textLines.Add(textLine.Finalize(options));
12351237
textLine = remaining;
1236-
i = 0;
1238+
i = -1;
12371239
lineAdvance = 0;
12381240
}
12391241
}
@@ -1326,7 +1328,11 @@ public void Add(
13261328
{
13271329
// Reset metrics.
13281330
// We track the maximum metrics for each line to ensure glyphs can be aligned.
1329-
this.ScaledLineAdvance += scaledAdvance;
1331+
if (graphemeIndex == 0)
1332+
{
1333+
this.ScaledLineAdvance += scaledAdvance;
1334+
}
1335+
13301336
this.ScaledMaxLineHeight = MathF.Max(this.ScaledMaxLineHeight, scaledLineHeight);
13311337
this.ScaledMaxAscender = MathF.Max(this.ScaledMaxAscender, scaledAscender);
13321338
this.ScaledMaxDescender = MathF.Max(this.ScaledMaxDescender, scaledDescender);
Lines changed: 3 additions & 0 deletions
Loading

tests/Images/ReferenceOutput/CountLinesWrappingLength_100-4.png

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Loading

tests/Images/ReferenceOutput/CountLinesWrappingLength_50-5.png

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading

0 commit comments

Comments
 (0)