-
Bug
-
Resolution: Unresolved
-
P3
-
8u131, 9
-
x86
-
os_x
FULL PRODUCT VERSION :
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+166)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+166, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
macOS Sierra 10.12.4
A DESCRIPTION OF THE PROBLEM :
Rendering text for the first time using GraphicContext.drawString or retrieving FontMetrics for the first time results in a long delay.
Both actions above will result in call to java.awt.Font.getFont2D() which ultimately calls a loadNativeFonts() method.
The delay is 2-3 seconds for both java 8 and java 9.
Applications that do not render text take about 1/5 the time to display results.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The included source code shows timings for displaying a window with and without text.
1) Run as is (NoText)
- baseline: renders graphics without text
2) Run with just Text() uncommented
- Example 1: renders text causing a delay in output (2-3s)
3) Run with just TextAfter() uncommented
- Example 2: renders graphics without text immediately, loads FontMetrics concurrently, once loading is done text rendering occurs with little / no delay.
The delay observed in #2 (DrawString) is about the same as the delay in #3 (getFontMetrics). Profiling shows sun.font.CFontManager.loadNativeFonts() takes most of this time.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Graphical displays without text rendering occurs sub-second after the JVM has been launched at least once. Keeping the response time sub-second with text rendering is desirable.
ACTUAL -
Windows appear frozen / blank for 2-3 seconds when first launched if any text is rendered to the screen.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package bugreport;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
/**
* Slow text rendering initialization.
* 2-3 second delay on macOS Sierra
* Core i7 (2.3 GHz)
*
*/
public class Sample {
static final long initTime = System.nanoTime();
static volatile long counter = 0;
public static void main(String[] args) throws InterruptedException {
Component comp = new // uncomment of the following lines
NoText()
// Text()
// TextAfter()
;
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(comp);
frame.setBounds(100, 0, 500, 500);
frame.setVisible(true);
for(int i = 0; i <= 1000; i++){
counter = i;
comp.repaint();
Thread.sleep(10);
}
}
}
/**
* Windows without text rendering come up quickly.
*/
class NoText extends Component{
static long initTime = System.nanoTime();
static long elapsedTime = -1;
public void paint(Graphics g) {
g.setColor(Color.GRAY);
g.fillRect(10, 0, getWidth() - 20, 10);
if(elapsedTime < 0){
elapsedTime = System.nanoTime() - initTime;
System.out.println((elapsedTime / 1_000_000) + " ms (init .. 1st render [no Text])");
}
}
}
/**
* Rendering text takes a while the first time.
*/
class Text extends Component{
static long initTime = System.nanoTime();
static long elapsedTime = -1;
public void paint(Graphics g) {
g.drawString("Hello World", 10, 30);
if(elapsedTime == -1) elapsedTime = System.nanoTime() - initTime;
g.drawString((elapsedTime / 1_000_000) + " ms (init .. 1st text render)", 10, 50);
g.setColor(Color.GRAY);
g.fillRect(10, 0, getWidth() - 20, 10);
}
}
/**
* Gets FontMetrics in a separate thread
* Start rending non text graphics immediately
* Once done the text rendering occurs little delay
*/
class TextAfter extends Component{
static long initTime = System.nanoTime();
static boolean FONT_INIT = false; // set true once FontMetric is retrieved
static long completeTime;
static long elapsedTime0; // first rendering (no text)
static long elapsedTime1; // FontLoaded
static long elapsedTime2 = -1; // first text rendering after FontLoaded
static{
new Thread(() ->{
new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY).createGraphics().getFontMetrics();
java.awt.EventQueue.invokeLater(() ->{
FONT_INIT = true;
completeTime = System.nanoTime();
elapsedTime1 = completeTime - initTime;
});
}).start();
}
public void paint(Graphics g) {
long width = (getWidth()-20) * Sample.counter / 1000;
g.setColor(Color.GRAY);
g.fillRect(10, 0, (int) width, 10);
if(FONT_INIT){
g.setColor(Color.BLACK);
g.drawString("Hello World", 10, 30);
if(elapsedTime2 < 0) elapsedTime2 = System.nanoTime() - completeTime;
g.drawString((elapsedTime0 / 1_000_000) +" ms (init .. 1st render)", 10, 50);
g.drawString((elapsedTime1 / 1_000_000) +" ms (init .. FontMetrics)", 10, 70);
g.drawString((elapsedTime2 / 1_000_000) +" ms (FontMetrics .. 1st text render)", 10, 90);
}
if(elapsedTime0 < 0) elapsedTime0 = System.nanoTime() - initTime;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Non-text can be rendered until font loading has been completed.
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+166)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+166, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
macOS Sierra 10.12.4
A DESCRIPTION OF THE PROBLEM :
Rendering text for the first time using GraphicContext.drawString or retrieving FontMetrics for the first time results in a long delay.
Both actions above will result in call to java.awt.Font.getFont2D() which ultimately calls a loadNativeFonts() method.
The delay is 2-3 seconds for both java 8 and java 9.
Applications that do not render text take about 1/5 the time to display results.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The included source code shows timings for displaying a window with and without text.
1) Run as is (NoText)
- baseline: renders graphics without text
2) Run with just Text() uncommented
- Example 1: renders text causing a delay in output (2-3s)
3) Run with just TextAfter() uncommented
- Example 2: renders graphics without text immediately, loads FontMetrics concurrently, once loading is done text rendering occurs with little / no delay.
The delay observed in #2 (DrawString) is about the same as the delay in #3 (getFontMetrics). Profiling shows sun.font.CFontManager.loadNativeFonts() takes most of this time.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Graphical displays without text rendering occurs sub-second after the JVM has been launched at least once. Keeping the response time sub-second with text rendering is desirable.
ACTUAL -
Windows appear frozen / blank for 2-3 seconds when first launched if any text is rendered to the screen.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package bugreport;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
/**
* Slow text rendering initialization.
* 2-3 second delay on macOS Sierra
* Core i7 (2.3 GHz)
*
*/
public class Sample {
static final long initTime = System.nanoTime();
static volatile long counter = 0;
public static void main(String[] args) throws InterruptedException {
Component comp = new // uncomment of the following lines
NoText()
// Text()
// TextAfter()
;
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(comp);
frame.setBounds(100, 0, 500, 500);
frame.setVisible(true);
for(int i = 0; i <= 1000; i++){
counter = i;
comp.repaint();
Thread.sleep(10);
}
}
}
/**
* Windows without text rendering come up quickly.
*/
class NoText extends Component{
static long initTime = System.nanoTime();
static long elapsedTime = -1;
public void paint(Graphics g) {
g.setColor(Color.GRAY);
g.fillRect(10, 0, getWidth() - 20, 10);
if(elapsedTime < 0){
elapsedTime = System.nanoTime() - initTime;
System.out.println((elapsedTime / 1_000_000) + " ms (init .. 1st render [no Text])");
}
}
}
/**
* Rendering text takes a while the first time.
*/
class Text extends Component{
static long initTime = System.nanoTime();
static long elapsedTime = -1;
public void paint(Graphics g) {
g.drawString("Hello World", 10, 30);
if(elapsedTime == -1) elapsedTime = System.nanoTime() - initTime;
g.drawString((elapsedTime / 1_000_000) + " ms (init .. 1st text render)", 10, 50);
g.setColor(Color.GRAY);
g.fillRect(10, 0, getWidth() - 20, 10);
}
}
/**
* Gets FontMetrics in a separate thread
* Start rending non text graphics immediately
* Once done the text rendering occurs little delay
*/
class TextAfter extends Component{
static long initTime = System.nanoTime();
static boolean FONT_INIT = false; // set true once FontMetric is retrieved
static long completeTime;
static long elapsedTime0; // first rendering (no text)
static long elapsedTime1; // FontLoaded
static long elapsedTime2 = -1; // first text rendering after FontLoaded
static{
new Thread(() ->{
new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY).createGraphics().getFontMetrics();
java.awt.EventQueue.invokeLater(() ->{
FONT_INIT = true;
completeTime = System.nanoTime();
elapsedTime1 = completeTime - initTime;
});
}).start();
}
public void paint(Graphics g) {
long width = (getWidth()-20) * Sample.counter / 1000;
g.setColor(Color.GRAY);
g.fillRect(10, 0, (int) width, 10);
if(FONT_INIT){
g.setColor(Color.BLACK);
g.drawString("Hello World", 10, 30);
if(elapsedTime2 < 0) elapsedTime2 = System.nanoTime() - completeTime;
g.drawString((elapsedTime0 / 1_000_000) +" ms (init .. 1st render)", 10, 50);
g.drawString((elapsedTime1 / 1_000_000) +" ms (init .. FontMetrics)", 10, 70);
g.drawString((elapsedTime2 / 1_000_000) +" ms (FontMetrics .. 1st text render)", 10, 90);
}
if(elapsedTime0 < 0) elapsedTime0 = System.nanoTime() - initTime;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Non-text can be rendered until font loading has been completed.