mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-26 16:15:39 +00:00
Added a hack to make shaped text wrap somehow correctly
This commit is contained in:
parent
45091547b7
commit
9e7b02291b
|
@ -332,6 +332,21 @@ std::string Font::wrapText(const std::string& text,
|
||||||
std::vector<std::pair<size_t, float>> dotsSection;
|
std::vector<std::pair<size_t, float>> dotsSection;
|
||||||
bool addDots {false};
|
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) {
|
for (size_t i {0}; i < text.length(); ++i) {
|
||||||
if (text[i] == '\n') {
|
if (text[i] == '\n') {
|
||||||
if (!multiLine) {
|
if (!multiLine) {
|
||||||
|
@ -376,7 +391,7 @@ std::string Font::wrapText(const std::string& text,
|
||||||
lineWidth += charWidth;
|
lineWidth += charWidth;
|
||||||
wrappedText.append(charEntry);
|
wrappedText.append(charEntry);
|
||||||
}
|
}
|
||||||
else if (!multiLine) {
|
else if (!multiLine && !skipAbbreviation) {
|
||||||
addDots = true;
|
addDots = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -390,13 +405,14 @@ std::string Font::wrapText(const std::string& text,
|
||||||
else if (lastSpace != 0) {
|
else if (lastSpace != 0) {
|
||||||
if (lastSpace + spaceAccum == wrappedText.size())
|
if (lastSpace + spaceAccum == wrappedText.size())
|
||||||
wrappedText.append("\n");
|
wrappedText.append("\n");
|
||||||
else
|
else if (!skipAbbreviation)
|
||||||
wrappedText[lastSpace + spaceAccum] = '\n';
|
wrappedText[lastSpace + spaceAccum] = '\n';
|
||||||
spaceOffset = lineWidth - lastSpacePos;
|
spaceOffset = lineWidth - lastSpacePos;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (lastSpace == 0)
|
if (lastSpace == 0)
|
||||||
++spaceAccum;
|
++spaceAccum;
|
||||||
|
if (!skipAbbreviation)
|
||||||
wrappedText.append("\n");
|
wrappedText.append("\n");
|
||||||
}
|
}
|
||||||
if (charEntry != " " && charEntry != "\t") {
|
if (charEntry != " " && charEntry != "\t") {
|
||||||
|
@ -452,6 +468,41 @@ glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
|
||||||
float yPos {0.0f};
|
float yPos {0.0f};
|
||||||
size_t cursor {0};
|
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) {
|
while (cursor < stop) {
|
||||||
unsigned int character {Utils::String::chars2Unicode(wrappedText, cursor)};
|
unsigned int character {Utils::String::chars2Unicode(wrappedText, cursor)};
|
||||||
if (character == '\n') {
|
if (character == '\n') {
|
||||||
|
@ -691,8 +742,8 @@ void Font::initLibrary()
|
||||||
|
|
||||||
void Font::shapeText(const std::string& text)
|
void Font::shapeText(const std::string& text)
|
||||||
{
|
{
|
||||||
// Calculate the hash value for the string to make sure we're not building segments
|
// Calculate the hash value for the string to make sure we're not shaping the same
|
||||||
// repeatedly for the same text.
|
// text repeatedly.
|
||||||
const size_t hashValue {std::hash<std::string> {}(text)};
|
const size_t hashValue {std::hash<std::string> {}(text)};
|
||||||
if (hashValue == mTextHash)
|
if (hashValue == mTextHash)
|
||||||
return;
|
return;
|
||||||
|
@ -771,7 +822,7 @@ void Font::shapeText(const std::string& text)
|
||||||
size_t cursor {0};
|
size_t cursor {0};
|
||||||
size_t length {0};
|
size_t length {0};
|
||||||
hb_glyph_info_t* glyphInfo {nullptr};
|
hb_glyph_info_t* glyphInfo {nullptr};
|
||||||
hb_glyph_position_t* glyphPos {nullptr};
|
// hb_glyph_position_t* glyphPos {nullptr};
|
||||||
unsigned int glyphCount {0};
|
unsigned int glyphCount {0};
|
||||||
|
|
||||||
// Step 2, shape text.
|
// Step 2, shape text.
|
||||||
|
@ -801,10 +852,17 @@ void Font::shapeText(const std::string& text)
|
||||||
if (segment.doShape) {
|
if (segment.doShape) {
|
||||||
character = glyphInfo[cursor].codepoint;
|
character = glyphInfo[cursor].codepoint;
|
||||||
++cursor;
|
++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 {
|
else {
|
||||||
// This also advances the cursor.
|
// This also advances the cursor.
|
||||||
character = Utils::String::chars2Unicode(segment.substring, 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);
|
segment.glyphIndexes.emplace_back(character);
|
||||||
|
|
|
@ -191,6 +191,7 @@ private:
|
||||||
struct ShapeSegment {
|
struct ShapeSegment {
|
||||||
unsigned int startPos;
|
unsigned int startPos;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
float glyphsWidth; // TEMPORARY
|
||||||
hb_font_t* fontHB;
|
hb_font_t* fontHB;
|
||||||
bool doShape;
|
bool doShape;
|
||||||
std::string substring;
|
std::string substring;
|
||||||
|
@ -199,6 +200,7 @@ private:
|
||||||
ShapeSegment()
|
ShapeSegment()
|
||||||
: startPos {0}
|
: startPos {0}
|
||||||
, length {0}
|
, length {0}
|
||||||
|
, glyphsWidth {0} // TEMPORARY
|
||||||
, fontHB {nullptr}
|
, fontHB {nullptr}
|
||||||
, doShape {false}
|
, doShape {false}
|
||||||
{
|
{
|
||||||
|
@ -207,7 +209,6 @@ private:
|
||||||
|
|
||||||
// Shape text using HarfBuzz.
|
// Shape text using HarfBuzz.
|
||||||
void shapeText(const std::string& text);
|
void shapeText(const std::string& text);
|
||||||
void shapeSegments(const std::string& text);
|
|
||||||
|
|
||||||
// Completely recreate the texture data for all textures based on mGlyphs information.
|
// Completely recreate the texture data for all textures based on mGlyphs information.
|
||||||
void rebuildTextures();
|
void rebuildTextures();
|
||||||
|
|
Loading…
Reference in a new issue