Table of contents
- Problem description;
- Step 1: Distill a sample;
- Step 2: Client code analysis;
- Step 3: Standard java library analysis;
- Step 4: Debug native code;
- Step 5: Dead end?;
- Step 6: Happy end;
IntelliJ IDEA's editor uses AWT primitives for all drawing (text, backgrounds, effects etc). Recently we've noticed that there is a problem with the '`' (backtick) symbol drawing using Inconsolata font. It looks as below (at least under Linux):
Ok, we see that the problem is observed during IntelliJ IDEA drawing but its rather inconvenient to use it for nailing the error down. Reasons: it takes time to start the IDE under IDE after the change; IJ uses a sophisticated processing on top of AWT drawing primitives; it's hard to submit the problem to Oracle if we need IJ to reproduce it etc.
So, I've built a simple Swing application that illustrates the problem - java web start link (assembled binary plus sources are available here).
Current assumption: there is a problem with the font
I've worked around the sample and have made the following observations:
- The problem occurs when we call Graphics.drawChars() with a string which length is more than one;
- All symbols that go after the backtick are displayed incorrectly;
Artifacts: real time web start start, assembled jar.
Conclusion: need to debug the processing
I've downloaded openjdk source bundle and configured it inside IntelliJ IDEA.
Further debugging shows that both types of drawing (draw a whole string VS draw by single symbols) use the same java state which is delivered to the native call DrawGlyphList::DrawGlyphList():
Conclusion: I need to debug the native code in order to find out the problem that occurs there.
Eventually I was able to build local jdk with debug info. Unfortunately, the problem is not reproduced under it. I'm mad.
Checked that the problem is not reproduced under openjdk6 as well. Looks like sun/oracle jre problem.
We can't find out the source of the problem, so, the only choice left is to provide a workaround at the client side. I don't how to call it (experience? luck?) but I managed to found another Inconsolata font that renders correctly - sample (tarball). That means that I can analyse the difference between the 'good' and 'bad' glyphs.
I've found out ability to detect problem glyphs from java - the property is GlyphMetrics.AdvanceY. The javadoc mentions 'advance' as follows:
'The advance width indicates the position at which AWT should place the next character'
Unfortunately, it mentions 'advance' attribute only in 'horizontal' perspective. Here we got a situation when the 'bad glyph' had non-zero 'y advance'. That produced exactly the observed effect - all subsequent symbols drawn at the same iteration were shifted vertically.
The solution was to check the font on the initialization an hold information about the problem glyphs. It looks as follows:
I'd call this happy end :)