Added a hack to make shaped text wrap somehow correctly

This commit is contained in:
Leon Styhre 2024-08-02 15:58:26 +02:00
parent 45091547b7
commit 9e7b02291b
2 changed files with 66 additions and 7 deletions

View file

@ -332,6 +332,21 @@ std::string Font::wrapText(const std::string& text,
std::vector<std::pair<size_t, float>> dotsSection;
bool addDots {false};
// TODO: This is a hack to avoid abbreviations and line breaks of shaped strings that actually
// fit within maxLength due to their length having been shortened by the shaping process.
// Proper line break support will need to be added for shaped strings as a long term solution.
// There are also many instances where this hack will not lead to correct results.
float totalWidth {0.0f};
bool skipAbbreviation {false};
shapeText(text);
for (auto& segment : mSegmentsHB)
totalWidth += segment.glyphsWidth;
if (totalWidth <= maxLength ||
(mSegmentsHB.size() == 1 && mSegmentsHB.front().glyphsWidth <= maxLength))
skipAbbreviation = true;
for (size_t i {0}; i < text.length(); ++i) {
if (text[i] == '\n') {
if (!multiLine) {
@ -376,7 +391,7 @@ std::string Font::wrapText(const std::string& text,
lineWidth += charWidth;
wrappedText.append(charEntry);
}
else if (!multiLine) {
else if (!multiLine && !skipAbbreviation) {
addDots = true;
break;
}
@ -390,14 +405,15 @@ std::string Font::wrapText(const std::string& text,
else if (lastSpace != 0) {
if (lastSpace + spaceAccum == wrappedText.size())
wrappedText.append("\n");
else
else if (!skipAbbreviation)
wrappedText[lastSpace + spaceAccum] = '\n';
spaceOffset = lineWidth - lastSpacePos;
}
else {
if (lastSpace == 0)
++spaceAccum;
wrappedText.append("\n");
if (!skipAbbreviation)
wrappedText.append("\n");
}
if (charEntry != " " && charEntry != "\t") {
wrappedText.append(charEntry);
@ -452,6 +468,41 @@ glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
float yPos {0.0f};
size_t cursor {0};
// TEMPORARY - enable this code when shaped text is properly wrapped in wrapText().
// shapeText(wrappedText);
// size_t totalPos {0};
// for (auto& segment : mSegmentsHB) {
// if (totalPos > stop)
// break;
// for (size_t i {0}; i < segment.glyphIndexes.size(); ++i) {
// ++totalPos;
// if (totalPos > stop)
// break;
// const unsigned int character {segment.glyphIndexes[i]};
// Glyph* glyph {nullptr};
// // Invalid character.
// if (!segment.doShape && character == 0)
// continue;
// if (!segment.doShape && character == '\n') {
// lineWidth = 0.0f;
// yPos += getHeight(lineSpacing);
// continue;
// }
// if (segment.doShape)
// glyph = getGlyphByIndex(character, segment.fontHB);
// else
// glyph = getGlyph(character);
// if (glyph)
// lineWidth += glyph->advance.x;
// }
// }
while (cursor < stop) {
unsigned int character {Utils::String::chars2Unicode(wrappedText, cursor)};
if (character == '\n') {
@ -691,8 +742,8 @@ void Font::initLibrary()
void Font::shapeText(const std::string& text)
{
// Calculate the hash value for the string to make sure we're not building segments
// repeatedly for the same text.
// Calculate the hash value for the string to make sure we're not shaping the same
// text repeatedly.
const size_t hashValue {std::hash<std::string> {}(text)};
if (hashValue == mTextHash)
return;
@ -771,7 +822,7 @@ void Font::shapeText(const std::string& text)
size_t cursor {0};
size_t length {0};
hb_glyph_info_t* glyphInfo {nullptr};
hb_glyph_position_t* glyphPos {nullptr};
// hb_glyph_position_t* glyphPos {nullptr};
unsigned int glyphCount {0};
// Step 2, shape text.
@ -801,10 +852,17 @@ void Font::shapeText(const std::string& text)
if (segment.doShape) {
character = glyphInfo[cursor].codepoint;
++cursor;
// TEMPORARY - should read native HarfBuzz size information instead.
Glyph* glyph {getGlyphByIndex(
character, segment.fontHB == nullptr ? mFontHB : segment.fontHB)};
segment.glyphsWidth += glyph->advance.x;
}
else {
// This also advances the cursor.
character = Utils::String::chars2Unicode(segment.substring, cursor);
// TEMPORARY - should read native HarfBuzz size information instead.
Glyph* glyph = getGlyph(character);
segment.glyphsWidth += glyph->advance.x;
}
segment.glyphIndexes.emplace_back(character);

View file

@ -191,6 +191,7 @@ private:
struct ShapeSegment {
unsigned int startPos;
unsigned int length;
float glyphsWidth; // TEMPORARY
hb_font_t* fontHB;
bool doShape;
std::string substring;
@ -199,6 +200,7 @@ private:
ShapeSegment()
: startPos {0}
, length {0}
, glyphsWidth {0} // TEMPORARY
, fontHB {nullptr}
, doShape {false}
{
@ -207,7 +209,6 @@ private:
// Shape text using HarfBuzz.
void shapeText(const std::string& text);
void shapeSegments(const std::string& text);
// Completely recreate the texture data for all textures based on mGlyphs information.
void rebuildTextures();