I am trying to render text with Harfbuzz and a signed distance field atlas.
The code is basically this:
void drawText(const std::wstring &str, Vec2 pos)
{
// Init harfbuzz
hb_buffer_t *hbBuf = hb_buffer_create();
hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR);
hb_buffer_set_script(hbBuf, HB_SCRIPT_LATIN);
hb_buffer_set_language(hbBuf, hb_language_from_string("en", 2));
// Process string
hb_buffer_add_utf32(hbBuf, reinterpret_cast<const uint32_t*>(str.c_str()), -1, 0, -1);
hb_shape(font.hb, hbBuf, nullptr, 0);
// Display string
unsigned int nbGlyphs;
hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(hbBuf, &nbGlyphs);
hb_glyph_position_t *glyphPos = hb_buffer_get_glyph_positions(hbBuf, &nbGlyphs);
for(unsigned int i = 0; i < nbGlyphs; i++)
{
Vec2 drawPos = pos + Vec2(glyphPos[i].x_offset, glyphPos[i].y_offset) / 64.f;
drawGlyph(glyphInfos[i].codepoint, drawPos);
pos.x += glyphPos[i].x_advance / 64.f;
pos.y += glyphPos[i].y_advance / 64.f;
}
}
The text looks correctly shaped for an English phrase, but when I test it with diacritics, they look misplaced.
I am testing it with aâa aâ̈a bb̂b bb̂̈b bb̧b bb͜b bb︠︡b
. The Unicode string does not contain precombined characters. Harfbuzz
uses the precombined character â
, which makes this one look good. Most other diacritics are off.
Text with diacritics on the left of where they should be
When I multiply x_offset
by 0.5
, the combining characters are better placed. The accents and the cedilla are at the right x position. The accents do not stack and are too low on the b
. The arc under BBB
(U+035C) should join the two last letters instead of being centered on the 2nd b
.
I also tried with U+FE20 and U+FE21 on the previous group of b
. In my tests, U+FE21 is on the 2nd b
, but it looks like it should be on the 3rd.
Test with glyphPos[i].x_offset * 0.5f
, better but still wrong
I tried with several fonts, but of those fonts, only NotoSansDisplay-Regular.ttf had combining characters. I did not manage to make a program display that string as expected on my Debian system (testing, with HarfBuzz 2.6.4-1).
With Windows, I got better results. Here is what I expect: the accents are stacked, the combining double breve below it at the right place, the cedilla is off.
Text rendering closer to what I expect
Am I doing something wrong with HarfBuzz, or I am testing to niche cases that HarfBuzz does support yet?
EDIT:
The actual problem was not described above.
I loaded a font with FreeType FT_New_Face
then created a hb_font_t
with hb_ft_font_create.
For every string drawn, I called FT_Set_Pixel_Sizes
but kept that hb_font_t
.
You should try shaping the same text and font with hb-view / hb-shape. That would help you narrow down where the problem is. I'm making a wild guess that the problem is in how / whether you are accounting for glyph origin in your atlas.