On Sat, 12 Dec 2020 22:31:56 GMT, Kevin Rushforth <k...@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

Reply via email to