FULL PRODUCT VERSION :
jdk 1.8.0_144 x64
ADDITIONAL OS VERSION INFORMATION :
Windows 7 64 SP1
A DESCRIPTION OF THE PROBLEM :
I have a loop that draws all glyphs of a font, and on each round does a snapshot to compute font bounding box up to current glyph.
With unifont-8.0.01.ttf, which supports many glyphs, exceptions are thrown for some (all?) code points between 0xFB1F and 0xFEFE.
Two exceptions are thrown:
1) One in what seems to be the rendering thread.
2) One by snapshot.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test case code.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception is thrown.
ACTUAL -
Exceptions in Canvas.snapshot(...) and QuantumRenderer.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.ArrayIndexOutOfBoundsException: -30
at com.sun.prism.impl.GlyphCache.getCachedGlyph(GlyphCache.java:246)
at com.sun.prism.impl.GlyphCache.render(GlyphCache.java:147)
at com.sun.prism.impl.ps.BaseShaderGraphics.drawString(BaseShaderGraphics.java:2101)
at com.sun.javafx.sg.prism.NGText.renderText(NGText.java:312)
at com.sun.javafx.sg.prism.NGText.renderContent2D(NGText.java:270)
at com.sun.javafx.sg.prism.NGShape.renderContent(NGShape.java:261)
at com.sun.javafx.sg.prism.NGCanvas.handleRenderOp(NGCanvas.java:1433)
at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:1097)
at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:606)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945)
at com.sun.javafx.tk.quantum.QuantumToolkit$5.draw(QuantumToolkit.java:1393)
at com.sun.javafx.tk.quantum.QuantumToolkit$5.run(QuantumToolkit.java:1429)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Unrecognized image loader: null
at javafx.scene.image.WritableImage.loadTkImage(WritableImage.java:240)
at javafx.scene.image.WritableImage.access$000(WritableImage.java:46)
at javafx.scene.image.WritableImage$1.loadTkImage(WritableImage.java:51)
at javafx.scene.Scene.doSnapshot(Scene.java:1236)
at javafx.scene.Node.doSnapshot(Node.java:1864)
at javafx.scene.Node.snapshot(Node.java:1942)
at bugz.JfxTextSnapshotMain.drawAndSnapshotLoop(JfxTextSnapshotMain.java:82)
at bugz.JfxTextSnapshotMain.access$0(JfxTextSnapshotMain.java:48)
at bugz.JfxTextSnapshotMain$1.run(JfxTextSnapshotMain.java:36)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:748)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class JfxTextSnapshotMain extends Application {
private static final boolean ANTI_BUG_MODIF_1 = false;
private static final boolean VARIANT_BUG_MODIF_1 = false;
private static final String UNIFONT_URL = "file:src/main/java/bugz/unifont-8.0.01.ttf";
private static final int FIRST_BAD_CODE_POINT = 0xFB1F;
private static final int LAST_BAD_CODE_POINT = 0xFEFE;
public static void main(String[] args) {
launch(args);
}
public JfxTextSnapshotMain() {
}
@Override
public void start(Stage primaryStage) {
final Pane root = new Pane();
final Scene scene = new Scene(root, 100.0, 100.0);
final Canvas canvas = new Canvas(100.0, 100.0);
root.getChildren().add(canvas);
final Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("drawAndSnapshotLoop()...");
System.out.flush();
try {
drawAndSnapshotLoop(canvas);
} finally {
System.out.println("...drawAndSnapshotLoop()");
System.out.flush();
}
}
};
Platform.runLater(runnable);
primaryStage.setScene(scene);
primaryStage.show();
}
private static void drawAndSnapshotLoop(Canvas canvas) {
final Font font = Font.loadFont(UNIFONT_URL, 12.0);
if (font == null) {
// Issue doesn't seem to happen with fonts that only have a few glyphs.
throw new AssertionError("font could not be loaded");
}
canvas.getGraphicsContext2D().setFont(font);
WritableImage img = new WritableImage(1,1);
for (int cp = FIRST_BAD_CODE_POINT - 10; cp <= LAST_BAD_CODE_POINT + 10; cp++) {
final String text = new String(new int[]{cp}, 0, 1);
if (ANTI_BUG_MODIF_1) {
// No issue if using strokeText(...).
canvas.getGraphicsContext2D().strokeText(text, 0, 0);
} else {
canvas.getGraphicsContext2D().fillText(text, 0, 0);
}
System.out.println("cp = 0x" + Integer.toHexString(cp).toUpperCase());
System.out.flush();
final WritableImage inputImg;
if (VARIANT_BUG_MODIF_1) {
// Reusing a (most often) large enough image prevents the
// IllegalArgumentException,
// but not the ArrayIndexOutOfBoundsException,
// which then occurs multiple times as the loop
// keeps running.
inputImg = img;
} else {
inputImg = null;
}
img = canvas.snapshot(null, inputImg);
}
}
}
---------- END SOURCE ----------