Skip to content

Commit

Permalink
Improve text wrapping when multiple characters are combined into one …
Browse files Browse the repository at this point in the history
…glyph.

#1923
  • Loading branch information
slime73 committed Sep 9, 2023
1 parent ddf88c6 commit 48e23a0
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 37 deletions.
44 changes: 27 additions & 17 deletions src/modules/font/GenericShaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,7 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran
float w = 0.0f;
float outwidth = 0.0f;
float widthbeforelastspace = 0.0f;
int wrapindex = -1;
int lastspaceindex = -1;
int firstindexafterspace = -1;

for (int i = (int)range.getMin(); i <= (int)range.getMax(); i++)
{
Expand All @@ -166,37 +165,48 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran

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.
if (isWhitespace(g))
{
lastspaceindex = i;
if (!isWhitespace(prevglyph))
widthbeforelastspace = w;
}
else
{
if (isWhitespace(prevglyph))
firstindexafterspace = i;

// Only wrap when there's a non-space character.
if (newwidth > wraplimit)
{
// 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)
*width = outwidth;

return wrapindex;
}

outwidth = newwidth;
}

w = newwidth;
prevglyph = g;
wrapindex = i;
}

if (width)
*width = outwidth;

return wrapindex;
// There wasn't any wrap in the middle of the range.
return range.last + 1;
}

} // font
Expand Down
6 changes: 3 additions & 3 deletions src/modules/font/TextShaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,10 @@ void TextShaper::getWrap(const ColoredCodepoints &codepoints, float wraplimit, s
float width = 0.0f;
int wrapindex = computeWordWrapIndex(codepoints, r, wraplimit, &width);

if (wrapindex >= (int) i)
if (wrapindex > (int) i)
{
r = Range(i, (size_t) wrapindex + 1 - i);
i = (size_t)wrapindex + 1;
r = Range(i, (size_t) wrapindex - i);
i = (size_t)wrapindex;
}
else
{
Expand Down
44 changes: 27 additions & 17 deletions src/modules/font/freetype/HarfbuzzShaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,7 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra
float w = 0.0f;
float outwidth = 0.0f;
float widthbeforelastspace = 0.0f;
int wrapindex = -1;
int lastspaceindex = -1;
int firstindexafterspace = -1;

uint32 prevcodepoint = 0;

Expand Down Expand Up @@ -376,38 +375,49 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra

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.
if (isWhitespace(clustercodepoint))
{
lastspaceindex = info.cluster;
if (!isWhitespace(prevcodepoint))
widthbeforelastspace = w;
}
else
{
if (isWhitespace(prevcodepoint))
firstindexafterspace = info.cluster;

// Only wrap when there's a non-space character.
if (newwidth > wraplimit)
{
// 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)
*width = outwidth;

return wrapindex;
}

outwidth = newwidth;
}

w = newwidth;
prevcodepoint = clustercodepoint;
wrapindex = info.cluster;
}
}

if (width)
*width = outwidth;

return wrapindex;
// There wasn't any wrap in the middle of the range.
return (int) range.last + 1;
}

} // freetype
Expand Down

0 comments on commit 48e23a0

Please sign in to comment.