Closed brawer closed 8 years ago
When rendering this text, fontdiff calls the following HarfBuzz functions on the buffer:
hb_buffer_add_utf16(); text="\u13a0\u030b\u0020\u13a1\u030b\u0020\u13a2\u030b\u0020\u13a3\u030b\u0020\u13a4\u030b\u0020\u13a5\u030b\u0020\u13a6\u030b\u0020\u13a7\u030b\u0020\u13a8\u030b\u0020\u13a9\u030b\u0020\u13aa\u030b\u0020\u13ab\u030b\u0020\u13ac\u030b\u0020\u13ad\u030b\u0020\u13ae\u030b\u0020\u13af\u030b"
hb_shape(); direction=ltr script=Cher language=chr length=47
After the call to hb_shape(), the result is:
glyph #0: info.codepoint=15 info.cluster=0 pos.x_advance=617 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #1: info.codepoint=9 info.cluster=1 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-350 pos.y_offset=137
glyph #2: info.codepoint=13 info.cluster=2 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #3: info.codepoint=17 info.cluster=3 pos.x_advance=562 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #4: info.codepoint=9 info.cluster=4 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-322 pos.y_offset=137
glyph #5: info.codepoint=13 info.cluster=5 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #6: info.codepoint=19 info.cluster=6 pos.x_advance=536 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #7: info.codepoint=9 info.cluster=7 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-309 pos.y_offset=137
glyph #8: info.codepoint=13 info.cluster=8 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #9: info.codepoint=21 info.cluster=9 pos.x_advance=674 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #10: info.codepoint=9 info.cluster=10 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-363 pos.y_offset=137
glyph #11: info.codepoint=13 info.cluster=11 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #12: info.codepoint=23 info.cluster=12 pos.x_advance=847 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #13: info.codepoint=9 info.cluster=13 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-600 pos.y_offset=137
glyph #14: info.codepoint=13 info.cluster=14 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #15: info.codepoint=25 info.cluster=15 pos.x_advance=260 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #16: info.codepoint=9 info.cluster=16 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-171 pos.y_offset=137
glyph #17: info.codepoint=13 info.cluster=17 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #18: info.codepoint=27 info.cluster=18 pos.x_advance=542 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #19: info.codepoint=9 info.cluster=19 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-312 pos.y_offset=137
glyph #20: info.codepoint=13 info.cluster=20 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #21: info.codepoint=29 info.cluster=21 pos.x_advance=630 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #22: info.codepoint=9 info.cluster=22 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-357 pos.y_offset=137
glyph #23: info.codepoint=13 info.cluster=23 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #24: info.codepoint=31 info.cluster=24 pos.x_advance=550 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #25: info.codepoint=9 info.cluster=25 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-442 pos.y_offset=137
glyph #26: info.codepoint=13 info.cluster=26 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #27: info.codepoint=33 info.cluster=27 pos.x_advance=578 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #28: info.codepoint=9 info.cluster=28 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-331 pos.y_offset=137
glyph #29: info.codepoint=13 info.cluster=29 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #30: info.codepoint=35 info.cluster=30 pos.x_advance=574 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #31: info.codepoint=9 info.cluster=31 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-328 pos.y_offset=137
glyph #32: info.codepoint=13 info.cluster=32 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #33: info.codepoint=37 info.cluster=33 pos.x_advance=455 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #34: info.codepoint=9 info.cluster=34 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-182 pos.y_offset=137
glyph #35: info.codepoint=13 info.cluster=35 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #36: info.codepoint=39 info.cluster=36 pos.x_advance=541 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #37: info.codepoint=9 info.cluster=37 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-288 pos.y_offset=137
glyph #38: info.codepoint=13 info.cluster=38 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #39: info.codepoint=41 info.cluster=39 pos.x_advance=768 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #40: info.codepoint=9 info.cluster=40 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-375 pos.y_offset=137
glyph #41: info.codepoint=13 info.cluster=41 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #42: info.codepoint=43 info.cluster=42 pos.x_advance=482 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #43: info.codepoint=9 info.cluster=43 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-292 pos.y_offset=178
glyph #44: info.codepoint=13 info.cluster=44 pos.x_advance=200 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #45: info.codepoint=45 info.cluster=45 pos.x_advance=591 pos.y_advance=0 pos.x_offset=0 pos.y_offset=0
glyph #46: info.codepoint=9 info.cluster=46 pos.x_advance=0 pos.y_advance=0 pos.x_offset=-278 pos.y_offset=137
Next step: Check whether pos.y_offset gets correctly passed to Cairo.
When computing coordinates for Cairo, it looks like x_offset wants to be added, but y_offset wants to be substracted. No idea why, but it seems to fix the problem, both in the left-to-right and right-to-left version.
cairo_glyph_t cairoGlyph;
cairoGlyph.index = glyphs[gi].codepoint;
cairoGlyph.x = (x + pos[gi].x_offset) / 64.0;
- cairoGlyph.y = (y + pos[gi].y_offset) / 64.0;
+ cairoGlyph.y = (y - pos[gi].y_offset) / 64.0;
x += pos[gi].x_advance;
y += pos[gi].y_advance;
cairoGlyphs.push_back(cairoGlyph);
Before the change:
After the change:
No idea why
Because fonts are in y-grows-up coordinate system while cairo is y-grows-down. You can negate the y-scale value you pass to hb_font_set_scale()
, or just do what you did now.
Very nice debugging! This also fixes our Arabic problem. I like a single fix that solves many issues :-)
@marekjez86, glad you like it! Actually, I didn’t even know we had a problem in Arabic. If you run into such problems, feel free to file bugs any time; it really helps for keeping track.
@behdad, thanks so much for the explanation! In that case, shouldn’t y_advance
also be negated?
cairo_glyph_t cairoGlyph;
cairoGlyph.index = glyphs[gi].codepoint;
cairoGlyph.x = (x + pos[gi].x_offset) / 64.0;
cairoGlyph.y = (y - pos[gi].y_offset) / 64.0;
x += pos[gi].x_advance;
- y += pos[gi].y_advance;
+ y -= pos[gi].y_advance;
I thought that without this change, Nastaliq rendering might be broken. But actually it works just fine, with or without negating y_advance
. Turns out that HarfBuzz always returns a zero y_advance
, also with Noto Nastaliq. Here’s a verse rendered by current fontdiff:
Y advance is used for vertical text, so if text is set horizontally then you will always get zero. Moving glyph vertically in horizontal text (e.g. in Nastaliq) will change the Y offset.
fontdiff uses Harfbuzz, but the shaping is currently broken sometimes.
To reproduce, use fontdiff on NotoSansCherokee-Regular.otf with the following command:
with the following
sample.html
file:Expected to see the same shapes as rendered by hb-view:
Observed: