Changed to having HarfBuzz set the horizontal glyph advance

This commit is contained in:
Leon Styhre 2024-08-03 14:09:51 +02:00
parent b4b498ba29
commit 4931ea9749
2 changed files with 29 additions and 19 deletions

View file

@ -43,7 +43,6 @@ Font::Font(float size, const std::string& path)
hb_blob_t* blobHB {hb_blob_create_from_file(fontPath.c_str())};
hb_face_t* faceHB {hb_face_create(blobHB, 0)};
mFontHB = hb_font_create(faceHB);
hb_font_set_ptem(mFontHB, mFontSize);
hb_face_destroy(faceHB);
hb_blob_destroy(blobHB);
@ -745,13 +744,13 @@ std::vector<Font::ShapeSegment> Font::shapeText(const std::string& text)
{
std::vector<ShapeSegment> segmentsHB;
hb_font_t* lastFont {nullptr};
unsigned int lastCursor {0};
unsigned int byteLength {0};
size_t lastCursor {0};
size_t byteLength {0};
size_t textCursor {0};
size_t lastFlushPos {0};
bool addSegment {false};
bool shapeSegment {true};
bool lastWasNoShaping {false};
size_t textCursor {0};
size_t lastFlushPos {0};
// Step 1, build segments.
@ -795,8 +794,8 @@ std::vector<Font::ShapeSegment> Font::shapeText(const std::string& text)
if (addSegment) {
ShapeSegment segment;
segment.startPos = lastFlushPos;
segment.length = textCursor - lastFlushPos;
segment.startPos = static_cast<unsigned int>(lastFlushPos);
segment.length = static_cast<unsigned int>(textCursor - lastFlushPos);
segment.fontHB = (lastFont == nullptr ? currGlyph->fontHB : lastFont);
segment.doShape = shapeSegment;
if (!shapeSegment)
@ -816,7 +815,7 @@ std::vector<Font::ShapeSegment> 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.
@ -828,15 +827,18 @@ std::vector<Font::ShapeSegment> Font::shapeText(const std::string& text)
if (segment.doShape) {
hb_buffer_reset(mBufHB);
hb_buffer_add_utf8(mBufHB, text.c_str(), text.length(), segment.startPos,
segment.length);
hb_buffer_add_utf8(mBufHB, text.c_str(), static_cast<int>(text.length()),
segment.startPos, segment.length);
hb_buffer_guess_segment_properties(mBufHB);
hb_font_set_scale(segment.fontHB, static_cast<int>(std::round(mFontSize * 256.0f)),
static_cast<int>(std::round(mFontSize * 256.0f)));
hb_shape(segment.fontHB, mBufHB, nullptr, 0);
if (hb_buffer_get_direction(mBufHB) == HB_DIRECTION_RTL)
segment.rightToLeft = true;
glyphInfo = hb_buffer_get_glyph_infos(mBufHB, &glyphCount);
glyphPos = hb_buffer_get_glyph_positions(mBufHB, &glyphCount);
length = glyphCount;
}
else {
@ -848,17 +850,19 @@ std::vector<Font::ShapeSegment> 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)};
// As HarfBuzz sometimes incorrectly indicates a zero advance we need to get the
// advance value from the glyph entry as it will in this case fall back to the
// built-in font advance value for the glyph.
Glyph* glyph {getGlyphByIndex(character,
segment.fontHB == nullptr ? mFontHB : segment.fontHB,
glyphPos[cursor].x_advance)};
segment.glyphsWidth += glyph->advance.x;
++cursor;
}
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);
Glyph* glyph {getGlyph(character)};
segment.glyphsWidth += glyph->advance.x;
}
@ -1061,7 +1065,7 @@ Font::Glyph* Font::getGlyph(const unsigned int id)
return &glyph;
}
Font::Glyph* Font::getGlyphByIndex(const unsigned int id, hb_font_t* fontArg)
Font::Glyph* Font::getGlyphByIndex(const unsigned int id, hb_font_t* fontArg, int xAdvance)
{
// Check if the glyph has already been loaded.
auto it = mGlyphMapByIndex.find(std::make_pair(id, fontArg));
@ -1118,7 +1122,13 @@ Font::Glyph* Font::getGlyphByIndex(const unsigned int id, hb_font_t* fontArg)
cursor.y / static_cast<float>(tex->textureSize.y)};
glyph.texSize = {glyphSize.x / static_cast<float>(tex->textureSize.x),
glyphSize.y / static_cast<float>(tex->textureSize.y)};
glyph.advance = {glyphSlot->metrics.horiAdvance >> 6, glyphSlot->metrics.vertAdvance >> 6};
// Sometimes HarfBuzz incorrectly indicates a zero advance so in this case we need to fall back
// to the font-default advance value for the glyph.
if (xAdvance == 0)
glyph.advance = {glyphSlot->metrics.horiAdvance >> 6, glyphSlot->metrics.vertAdvance >> 6};
else
glyph.advance = {static_cast<int>(std::round(static_cast<float>(xAdvance) / 256.0f)),
glyphSlot->metrics.vertAdvance >> 6};
glyph.bearing = {glyphSlot->metrics.horiBearingX >> 6, glyphSlot->metrics.horiBearingY >> 6};
glyph.rows = glyphSize.y;

View file

@ -224,7 +224,7 @@ private:
FT_Face* getFaceForChar(unsigned int id);
FT_Face* getFaceForGlyphIndex(unsigned int id, hb_font_t* fontArg);
Glyph* getGlyph(const unsigned int id);
Glyph* getGlyphByIndex(const unsigned int id, hb_font_t* fontArg);
Glyph* getGlyphByIndex(const unsigned int id, hb_font_t* fontArg, int xAdvance = 0);
float getNewlineStartOffset(const std::string& text,
const unsigned int& charStart,