JDK-8269888: Thai text rendered incorrectly using some AffineTransform-derived fonts

Daniel Gredler djgredler at gmail.com
Tue Sep 7 23:43:33 UTC 2021


Hi all,

I'm trying to figure out a fix for JDK-8269888 [1]. The font that I'm using
to replicate the issue, Google Noto Sans Thai Regular [2], uses the GPOS
table internally. It looks like the GPOS adjustment in HB is a two-step
process, where HB first sets the glyph position x_offset using anchor data
from the GPOS table [3], and then adjusts that x_offset using existing
x_advance data [4], all coordinated via the
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT scratch flag.

Internally, OpenJDK is using the font_funcs virtual method functionality
[5] to customize most of the font property callbacks [6]. Java provides
users two ways to customize the size of a font: you can set the pt size, or
you can set an affine transform (scale, rotate, shear, translate, etc).
When you use the pt size approach, OpenJDK calls hb_font_set_scale with the
appropriate pt size [7]. However, when a scaling affine transform is used,
the pt size is technically unchanged, and a value of 1pt is used. Usually
this works fine, because Java's font_funcs callbacks are providing scaled
origin and advance numbers back to HB, but this breaks the two-step GPOS
attachment logic: the first step is not aware of the scaling applied by the
OpenJDK font_funcs callbacks (especially the
hb_font_get_glyph_h_advance_func_t), but the second step uses a scaled
advance value provided by an OpenJDK callback. In practice, at e.g. x50
scaling, this means that the first step sets the x_offset to a relatively
small value (e.g. 32899), but the second step adjusts the x_offset by a
relatively large value (e.g. 1612184).

A possible fix would be for OpenJDK to take the affine transform scale into
account when setting the font size via hb_font_set_scale, and the HarfBuzz
team has confirmed that this seems like the sensible approach [8]. In fact,
it seems like prior to 2016 this was indeed the case [9], but the logic was
changed to fix JDK-8145901 (Printed content is overlapping). JDK-8145901
doesn't seem to be public in the bug tracker, and I'm not sure where to
find the HB_NODEVTX trigger used to request initialization of devScale in
HBShaper.c, so I'm not sure how to fix JDK-8269888 without risking a
regression on JDK-8145901. Is devScale still needed? Can we use xPtSize and
yPtSize (instead of ptSize*devScale) in _hb_jdk_font_create() and
_hb_jdk_ct_font_create()? I've confirmed that using xPtSize and yPtSize
fixes the Thai text rendering use case, at least.

Thanks!

Daniel

[1] https://bugs.openjdk.java.net/browse/JDK-8269888
[2] https://www.google.com/get/noto/#sans-thai
[3]
https://github.com/harfbuzz/harfbuzz/blob/bbeb3a62b0efbb598d8683f7c4b6cc7069a58aeb/src/hb-ot-layout-gpos-table.hh#L708
[4]
https://github.com/harfbuzz/harfbuzz/blob/bbeb3a62b0efbb598d8683f7c4b6cc7069a58aeb/src/hb-ot-layout-gpos-table.hh#L2922
[5] https://harfbuzz.github.io/fonts-and-faces-custom-functions.html
[6]
https://github.com/openjdk/jdk/blob/005d8a7fca8b4d9519d2bde0a7cdbbece1cd3981/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc#L271
[7]
https://github.com/openjdk/jdk/blob/005d8a7fca8b4d9519d2bde0a7cdbbece1cd3981/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc#L422
[8] https://github.com/harfbuzz/harfbuzz/discussions/3191
[9]
https://github.com/openjdk/jdk/commit/5935292ae022e970bd4075de4d704719f3b05575#diff-6a155985752d3cc5ca8a74d4bf51c899d80ea0337e30029a4fafe856893456f3L327-L328



More information about the client-libs-dev mailing list