RFR: 8211294: [windows] TextArea content is blurry with 125% scaling

Frederic Thevenet fthevenet at openjdk.java.net
Mon Dec 14 11:20:00 UTC 2020


On Sat, 12 Dec 2020 22:31:56 GMT, Kevin Rushforth <kcr at openjdk.org> wrote:

>> I spent a bit of time looking at this. I think the root cause of the problem is in ScrollPane itself. It is attempting to layout its children by doing a snap to pixel (meaning that the final scaled translation should be an integer value), but it is failing to do so. This is mostly not a problem when caching is disabled, since our text rendering does sub-pixel antialiasing that looks crisp even at non-integer boundaries. However, translating an already-rendered image by a non-integer boundary will cause the blurriness we are seeing. There is another issue with the Y translation which isn't 0 even when  not using a ScrollPane.
>> 
>> I'll continue looking at this in the coming week.
>
> One more comment: given the quality problems that necessarily arise when the translation of a cached image is not on an integer boundary, part of the solution might be to snap the cached image to a pixel boundary as is done in this PR, but we would need to ensure that this doesn't impact smooth scrolling of a TextArea.

Further investigations on my part raised one more question, which hopefully you can answer:
To which extend should `setSnapToPixel` ensure children of a region are indeed snap to whole pixel coordinates?

To make it clearer, please consider the following sample:
 java
public class Blur extends Application {
    @Override
    public void start(final Stage stage) throws Exception {
        var root = new Pane();
        root.setSnapToPixel(true);
        var ctrl = new CheckBox("Cached");

        ctrl.setLayoutX(0.5);
        ctrl.setLayoutY(0.5);
        ctrl.cacheProperty().bind(ctrl.selectedProperty());
        ctrl.setSelected(true);

        var ctrl2 = new Button("Foo");
        ctrl2.setLayoutX(0.5);
        ctrl2.setLayoutY(30.5);
        ctrl2.cacheProperty().bind(ctrl.selectedProperty());

        var ctrl3 = new Button("Bar");
        ctrl3.setLayoutY(60);
        ctrl3.cacheProperty().bind(ctrl.selectedProperty());

        root.getChildren().addAll(ctrl, ctrl2, ctrl3);
        Scene scene;
        scene = new Scene(root, 200, 200);

        stage.setTitle("Blur test");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {

        launch(args);
    }
}

In this sample, LayoutX and Y properties are deliberately set to non integer values for the first two controls (the last one serves as a visual baseline, but `snapToPixel` is  set to true. Also clicking the check box toggles caching for all controls.

Here's what it looks looks **at 100% scaling**, (OpenJFX 15.0.1), with cache enabled:
![image](https://user-images.githubusercontent.com/7450507/102073943-57471680-3e04-11eb-95f5-753fa545a64b.png)

and with cache disabled:
![image](https://user-images.githubusercontent.com/7450507/102073975-5f9f5180-3e04-11eb-97e7-41bb722241af.png)

What is the legitimate result to expect here; should `root.setSnapToPixel(true);` override `setLayoutX(0.5);` and align everything for crisp rendering (as is my understanding)? Or am I misunderstanding the scope of `setSnapToPixel` and it has no effect when layout is set explicitly?

-------------

PR: https://git.openjdk.java.net/jfx/pull/308


More information about the openjfx-dev mailing list