[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