JDK-8136593 : Font kerning/anti-aliasing looks wrong, particularly on non-Retina screen
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8u60
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: other
  • CPU: x86
  • Submitted: 2015-09-16
  • Updated: 2018-09-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Yosemite 10.10.5

EXTRA RELEVANT SYSTEM CONFIGURATION :
MacBook Pro 13", Retina, with external, non-Retina screen attached via DisplayPort.

A DESCRIPTION OF THE PROBLEM :
Font rendering looks wrong when certain characters are adjacent, it looks acceptable on the Retina screen, but less so on the non-Retina screen. I have screenshots demonstrating the issue.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Standard system font on JavaFX button, with characters 'r' and 't' adjacent, i.e. I have a button with:

'Let's get started...' where the r and t in 'started' looks wrong.

Making a new FXML project in NetBeans, and putting 'Let's get started...' into the button will demonstrate the issue.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect the text to be kerned correctly on both screens.
ACTUAL -
On the Retina screen, the text appears acceptable kerned (not sure if it's 100% correct), but on the non-Retina, it's notably different.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package kernfx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author gt
 */
public class KernFX extends Application {
    
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        
        Scene scene = new Scene(root);
        
        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
}




/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package kernfx;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

/**
 *
 * @author gt
 */
public class FXMLDocumentController implements Initializable {
    
    @FXML
    private Label label;
    
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
    
}





<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="kernfx.FXMLDocumentController">
    <children>
        <Button layoutX="126" layoutY="90" text="Let's get started..." />

    </children>
</AnchorPane>

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround, other than to use a Retina screen.


Comments
As text2 shows the same sequence looks OK some of the time, so rounding at some fractional positions seems to plays a role here. It may even be that it is a problem with truncating the "r" instead of overwriting it when drawing the "t". So perhaps this is not entirely the same thing as the more noticeable case with cursive scripts.
21-09-2015

I've reproduced this and it is not grayscale text, it is LCD text and what we seem to have here is the "t" overlapping the "r" in "started". The problem is that we are not reading back the surface after drawing each glyph, so we just write over par of the r. In the retina case, there is more resolution and the glyphs do not overlap. See the attached image.
21-09-2015

I am sure there is a bug discussing this, but I cannot locate it right now. I assume you get greyscale text (not subpixel LCD), in which case you may not have sub-pixel positioning. We accumulate total advance in floating point and need the sub-pixel positioning to help with positioning as close to the ideal fractional position as possible. As such the greyscale glyphs which don't support this are prone to uneven spacing. We would need to produce grey glyphs that are tuned to 0.5 or maybe 0.25 pixels and use the appropriate one. Hmm. I thought the coretext code path had support for this but it looks like it may have to be enabled by a property. Can the submitter please report if either of these help (or change things at all, even if you don't think it is better) : -Dprism.subpixeltext=on -Dprism.subpixeltext=native In fact, "on" should be the default and native seems like it may not apply to OSX. So in theory at least, it should be doing this already. Will have to try this myself to see.
21-09-2015