Improve text wrapping when multiple characters are combined into one glyph.

#1923
This commit is contained in:
Sasha Szpakowski
2023-09-08 22:38:17 -03:00
parent ddf88c64bd
commit 48e23a048d
3 changed files with 57 additions and 37 deletions
+29 -19
View File
@@ -151,8 +151,7 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran
float w = 0.0f; float w = 0.0f;
float outwidth = 0.0f; float outwidth = 0.0f;
float widthbeforelastspace = 0.0f; float widthbeforelastspace = 0.0f;
int wrapindex = -1; int firstindexafterspace = -1;
int lastspaceindex = -1;
for (int i = (int)range.getMin(); i <= (int)range.getMax(); i++) for (int i = (int)range.getMin(); i <= (int)range.getMax(); i++)
{ {
@@ -166,31 +165,28 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran
float newwidth = w + getKerning(prevglyph, g) + getGlyphAdvance(g); float newwidth = w + getKerning(prevglyph, g) + getGlyphAdvance(g);
// Only wrap when there's a non-space character.
if (newwidth > wraplimit && !isWhitespace(g))
{
// Rewind to the last seen space when wrapping.
if (lastspaceindex != -1)
{
wrapindex = lastspaceindex;
outwidth = widthbeforelastspace;
}
break;
}
// Don't count trailing spaces in the output width. // Don't count trailing spaces in the output width.
if (isWhitespace(g)) if (isWhitespace(g))
{ {
lastspaceindex = i;
if (!isWhitespace(prevglyph)) if (!isWhitespace(prevglyph))
widthbeforelastspace = w; widthbeforelastspace = w;
} }
else else
outwidth = newwidth; {
if (isWhitespace(prevglyph))
firstindexafterspace = i;
w = newwidth; // Only wrap when there's a non-space character.
prevglyph = g; if (newwidth > wraplimit)
wrapindex = i; {
// If this is the first character, wrap from the next one instead of this one.
int wrapindex = i > (int)range.first ? i : (int)range.first + 1;
// Rewind to after the last seen space when wrapping.
if (firstindexafterspace != -1)
{
wrapindex = firstindexafterspace;
outwidth = widthbeforelastspace;
} }
if (width) if (width)
@@ -199,5 +195,19 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran
return wrapindex; return wrapindex;
} }
outwidth = newwidth;
}
w = newwidth;
prevglyph = g;
}
if (width)
*width = outwidth;
// There wasn't any wrap in the middle of the range.
return range.last + 1;
}
} // font } // font
} // love } // love
+3 -3
View File
@@ -303,10 +303,10 @@ void TextShaper::getWrap(const ColoredCodepoints &codepoints, float wraplimit, s
float width = 0.0f; float width = 0.0f;
int wrapindex = computeWordWrapIndex(codepoints, r, wraplimit, &width); int wrapindex = computeWordWrapIndex(codepoints, r, wraplimit, &width);
if (wrapindex >= (int) i) if (wrapindex > (int) i)
{ {
r = Range(i, (size_t) wrapindex + 1 - i); r = Range(i, (size_t) wrapindex - i);
i = (size_t)wrapindex + 1; i = (size_t)wrapindex;
} }
else else
{ {
+30 -20
View File
@@ -335,8 +335,7 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra
float w = 0.0f; float w = 0.0f;
float outwidth = 0.0f; float outwidth = 0.0f;
float widthbeforelastspace = 0.0f; float widthbeforelastspace = 0.0f;
int wrapindex = -1; int firstindexafterspace = -1;
int lastspaceindex = -1;
uint32 prevcodepoint = 0; uint32 prevcodepoint = 0;
@@ -376,32 +375,28 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra
float newwidth = w + floorf((glyphpos.x_advance >> 6) / dpiScales[0] + 0.5f); float newwidth = w + floorf((glyphpos.x_advance >> 6) / dpiScales[0] + 0.5f);
// Only wrap when there's a non-space character.
if (newwidth > wraplimit && !isWhitespace(clustercodepoint))
{
// Rewind to the last seen space when wrapping.
if (lastspaceindex != -1)
{
wrapindex = lastspaceindex;
outwidth = widthbeforelastspace;
}
break;
}
// Don't count trailing spaces in the output width. // Don't count trailing spaces in the output width.
if (isWhitespace(clustercodepoint)) if (isWhitespace(clustercodepoint))
{ {
lastspaceindex = info.cluster;
if (!isWhitespace(prevcodepoint)) if (!isWhitespace(prevcodepoint))
widthbeforelastspace = w; widthbeforelastspace = w;
} }
else else
outwidth = newwidth; {
if (isWhitespace(prevcodepoint))
firstindexafterspace = info.cluster;
w = newwidth; // Only wrap when there's a non-space character.
prevcodepoint = clustercodepoint; if (newwidth > wraplimit)
wrapindex = info.cluster; {
} // If this is the first character, wrap from the next one instead of this one.
int wrapindex = info.cluster > (int) range.first ? info.cluster : (int) range.first + 1;
// Rewind to after the last seen space when wrapping.
if (firstindexafterspace != -1)
{
wrapindex = firstindexafterspace;
outwidth = widthbeforelastspace;
} }
if (width) if (width)
@@ -410,6 +405,21 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra
return wrapindex; return wrapindex;
} }
outwidth = newwidth;
}
w = newwidth;
prevcodepoint = clustercodepoint;
}
}
if (width)
*width = outwidth;
// There wasn't any wrap in the middle of the range.
return (int) range.last + 1;
}
} // freetype } // freetype
} // font } // font
} // love } // love