RFR: 8264591: HBox/VBox child widths pixel-snap to wrong value [v7]

John Hendrikx jhendrikx at openjdk.org
Tue Apr 25 18:41:20 UTC 2023


On Tue, 25 Apr 2023 17:55:20 GMT, Andy Goryachev <angorya at openjdk.org> wrote:

> > It's logical width can take on any multiple of the physical pixel size divided by the render scale, which is 1 / 1.5 = 0.66.
> 
> No it cannot. Snapping imposes limitation on which logical coordinates are acceptable. What's more, the distance between two adjacent acceptable logical coordinates is not the same.

Snapping turns physical coordinates into integers as you can't have half pixels.  Pixels are uniformly spaced.  Converting a pixel offset back to a logical coordinate leads to a fractional value, but any pixel offset can be converted back, and the snapped logical coordinates will be uniformly spaced because of that.
 
> Let's take a look at an example. We are going to use logical coordinates only, because these are used for constraints as well as in the layout. Here is a list of acceptable snapped logical coordinates for scale=1.5 again:
> 
> ```
> scale=1.5
> x=1 snapped=1.333 step=1.333
> x=2 snapped=2.000 step=0.667
> x=3 snapped=3.333 step=1.333
> x=4 snapped=4.000 step=0.667
> x=5 snapped=5.333 step=1.333
> ```

What about:

x = 0.5 snapped = 0.666
x = 2.5 snapped = 2.666

?

> (the fact that x are integers is irrelevant, we are not limited to integers, it's just to illustrate a point).
> 
> So let's have two nodes with fixed size of 1 (min = max = 1). The first one is positioned at x=0 and has the width of 1.333. The second is positioned at x=1.333 and has a width of 0.667.

Why would the 2nd node have a width of 0.667?  That would be below its minimum allowed value.  It will be 1.333 just like the first node.  The container will ensure that its minimum value takes the snapping into account, so it will report a logical minimum of 2.666 (ie. exactly 4 pixels).

The min/max values are not strictly honored when snapping is on, they're snapped first.  So `min = max = 1` would become `min = max = ceil(1 * 1.5) / 1.5 = 1.333`.  It's therefore possible that the minimum size of a control won't reach the logical minimum value if that minimum is not an exact number of pixels.  The maximum can even be exceeded by up to 1/1.5.

> To summarize, snapping and fractional scale under certain circumstances (*) leads to:
> 
> * honoring constraints might be impossible
> * moving a single node requires a new layout pass
> * possible danger of infinite loop cycling between 2+ layout states
> 
> (*) the circumstances are: nodes having grow property set.

I only agree with the first point, because constraints are snapped and therefore may be slightly different than their logical values, but this rule applies in all cases:

     snapped constraint >= logical constraint

... and, as constraints are spaces, they are always rounded up when snapping.

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

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


More information about the openjfx-dev mailing list