[HarfBuzz] x_offset too small for a combining character
Ondřej Majerech
majerech.o at gmail.com
Mon Dec 5 02:56:10 UTC 2016
Hello,
I'm trying to use HarfBuzz together with FreeType2 to render Unicode
text. I got plain English working, but ran into an issue as soon as I
tried to render a string that uses combining characters. Specifically,
I tried to render q̣̇ -- lowercase q with a dot above and below,
U+0071 U+0307 U+0323. In my program, the dots are rendered to the
right of the q character, instead of them being centered horizontally.
After a bit of debugging, I discovered that HarfBuzz gives me too
small a value for the x_offset of the combining characters, which
makes my program offset them by just one pixel from the pen position.
One pixel is definitely not enough to center those dots.
I threw together a testcase program that demonstrates my issue:
int
main() {
// [q] [U+0307 COMBINING DOT ABOVE] [U+0323 COMBINING DOT BELOW]
char text[] = "q\314\207\314\243";
FT_Library library;
FT_Init_FreeType(&library);
FT_Face face;
FT_New_Face(library, "DejaVuSans.ttf", 0, &face);
FT_Set_Char_Size(face, 12 << 6, 12 << 6, 96, 96);
hb_font_t* font = hb_ft_font_create(face, nullptr);
hb_buffer_t* buffer = hb_buffer_create();
hb_buffer_add_utf8(buffer, text, sizeof text - 1, 0, sizeof text - 1);
hb_buffer_guess_segment_properties(buffer);
hb_shape(font, buffer, nullptr, 0);
unsigned num_glyphs;
hb_glyph_position_t* positions =
hb_buffer_get_glyph_positions(buffer, &num_glyphs);
hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, nullptr);
for (unsigned i = 0; i < num_glyphs; ++i) {
char name_buffer[1024];
FT_Get_Glyph_Name(face, infos[i].codepoint, name_buffer, sizeof
name_buffer);
std::cout << name_buffer << ": "
<< "x_advance = " << (positions[i].x_advance / 64)
<< ", y_advance = " << (positions[i].y_advance / 64)
<< ", x_offset = " << (positions[i].x_offset / 64)
<< ", y_offset = " << (positions[i].y_offset / 64)
<< '\n';
}
}
Running this program, I get the following output:
q: x_advance = 10, y_advance = 0, x_offset = 0, y_offset = 0
dotbelowcomb: x_advance = 0, y_advance = 0, x_offset = -1, y_offset = -3
uni0307: x_advance = 0, y_advance = 0, x_offset = -1, y_offset = 0
The offending part of that output are the two instances of x_offset =
-1 in there -- my renderer uses very similar code to get pixel
positions of the glyphs for rendering -- getting -1's there means the
renderer moves back just one pixel, which results in the dots being on
the right side of the q character.
If I run `hb-view ./DejaVuSans.ttf q̣̇`, the combining dots are
centered correctly. Running `hb-shape --font-size 12 ./DejaVuSans.ttf
q̣̇` produces the following output:
[q=0+41|dotbelowcomb=0 at -34,-3+0|uni0307=0 at -34,0+0]
Which again looks okay to me -- HB wants to offset the combining dots
some considerable distance to the left, which is what I would expect.
So the question is, what am I doing wrong in my program that makes
HarfBuzz report such low x_offset values? I based my code mostly on
the Hello HarfBuzz code from the documentation, but apparently I
missed something.
I'll appreciate any suggestions on how to use HarfBuzz correctly so as
to get the proper x_offset values.
~ Ondra
More information about the HarfBuzz
mailing list