On Tue, 3 Jan 2023 06:31:37 GMT, Michael Strauß <mstra...@openjdk.org> wrote:

>> The children of HBox/VBox don't always pixel-snap to the same value as the 
>> container itself when a render scale other than 1 is used. This can lead to 
>> a visual glitch where the content bounds don't line up with the container 
>> bounds. In this case, the container will extend beyond its content, or vice 
>> versa.
>> 
>> The following program shows the problem for HBox:
>> 
>> Region r1 = new Region();
>> Region r2 = new Region();
>> Region r3 = new Region();
>> Region r4 = new Region();
>> Region r5 = new Region();
>> Region r6 = new Region();
>> r1.setBackground(new Background(new BackgroundFill(Color.GREY, null, null)));
>> r2.setBackground(new Background(new BackgroundFill(Color.DARKGRAY, null, 
>> null)));
>> r3.setBackground(new Background(new BackgroundFill(Color.BLACK, null, 
>> null)));
>> r4.setBackground(new Background(new BackgroundFill(Color.GREY, null, null)));
>> r5.setBackground(new Background(new BackgroundFill(Color.DARKGRAY, null, 
>> null)));
>> r6.setBackground(new Background(new BackgroundFill(Color.BLACK, null, 
>> null)));
>> r1.setPrefWidth(25.3);
>> r2.setPrefWidth(25.3);
>> r3.setPrefWidth(25.4);
>> r4.setPrefWidth(25.3);
>> r5.setPrefWidth(25.3);
>> r6.setPrefWidth(25.4);
>> r1.setMaxHeight(30);
>> r2.setMaxHeight(30);
>> r3.setMaxHeight(30);
>> r4.setMaxHeight(30);
>> r5.setMaxHeight(30);
>> r6.setMaxHeight(30);
>> HBox hbox1 = new HBox(r1, r2, r3, r4, r5, r6);
>> hbox1.setBackground(new Background(new BackgroundFill(Color.RED, null, 
>> null)));
>> hbox1.setPrefHeight(40);
>> 
>> r1 = new Region();
>> r2 = new Region();
>> r3 = new Region();
>> r4 = new Region();
>> r5 = new Region();
>> r6 = new Region();
>> r1.setBackground(new Background(new BackgroundFill(Color.GREY, null, null)));
>> r2.setBackground(new Background(new BackgroundFill(Color.DARKGRAY, null, 
>> null)));
>> r3.setBackground(new Background(new BackgroundFill(Color.BLACK, null, 
>> null)));
>> r4.setBackground(new Background(new BackgroundFill(Color.GREY, null, null)));
>> r5.setBackground(new Background(new BackgroundFill(Color.DARKGRAY, null, 
>> null)));
>> r6.setBackground(new Background(new BackgroundFill(Color.BLACK, null, 
>> null)));
>> r1.setPrefWidth(25.3);
>> r2.setPrefWidth(25.3);
>> r3.setPrefWidth(25.4);
>> r4.setPrefWidth(25.3);
>> r5.setPrefWidth(25.3);
>> r6.setPrefWidth(25.4);
>> r1.setMaxHeight(30);
>> r2.setMaxHeight(30);
>> r3.setMaxHeight(30);
>> r4.setMaxHeight(30);
>> r5.setMaxHeight(30);
>> r6.setMaxHeight(30);
>> HBox hbox2 = new HBox(r1, r2, r3, r4, r5, r6);
>> hbox2.setBackground(new Background(new BackgroundFill(Color.RED, null, 
>> null)));
>> hbox2.setPrefHeight(40);
>> hbox2.setPrefWidth(152);
>> 
>> VBox root = new VBox(new HBox(hbox1), new HBox(hbox2));
>> root.setSpacing(20);
>> Scene scene = new Scene(root, 500, 250);
>> 
>> primaryStage.setScene(scene);
>> primaryStage.show();
>> 
>> 
>> Here's a before-and-after comparison of the program above after applying the 
>> fix. Note that 'before', the backgrounds of the container (red) and its 
>> content (black) don't align perfectly. The render scale is 175% in this 
>> example.
>> ![pixel-glitch](https://user-images.githubusercontent.com/43553916/112891996-146e2d80-90d9-11eb-9d83-97754ae38dc1.png)
>> 
>> I've filed a bug report and will change the title of the GitHub issue as 
>> soon as it's posted.
>
> Michael Strauß has updated the pull request with a new target base due to a 
> merge or a rebase. The pull request now contains 12 commits:
> 
>  - changes per review
>  - Merge branch 'master' into fixes/box-snap-to-pixel
>    
>    # Conflicts:
>    #  
> modules/javafx.graphics/src/test/java/test/javafx/scene/layout/HBoxTest.java
>    #  
> modules/javafx.graphics/src/test/java/test/javafx/scene/layout/VBoxTest.java
>  - Merge branch 'openjdk:master' into fixes/box-snap-to-pixel
>  - revert snappedSum
>  - don't call snappedSum in hot loop
>  - Improved code documentation
>  - Merge branch 'master' into fixes/box-snap-to-pixel
>  - changed some method names, make test config a local class
>  - added documentation, improved method names
>  - Merge branch 'master' into fixes/box-snap-to-pixel
>  - ... and 2 more: https://git.openjdk.org/jfx/compare/a35c3bf7...fbbc273a

I've put some additional time into this, and I can only conclude that when 
snapping is on, that every float calculation that is performed (even something 
as simple as an addition) must be rounded to pixel boundaries or you risk 
propagating a tiny error that will result in a comparison going the other way 
in some edge case.

I've now implemented an alternative in #1111 and to get all tests to perform 
exactly right and exactly when you'd expect to see a pixel added here or there, 
a lot of pixel boundary rounding is a requirement... so much so that I wonder 
if it really is wise to do this with floats -- it may be wiser to multiply 
everything by render scale first, do the calculations with integers, then 
restore it to floats.  I added @mstr2 's test to this one as well, and it 
passed unchanged.

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

PR Comment: https://git.openjdk.org/jfx/pull/445#issuecomment-1519115376

Reply via email to