On Sat, 12 Dec 2020 22:31:56 GMT, Kevin Rushforth <[email protected]> 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:

and with cache disabled:

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