This PR formalizes render scale and snapping policy as an inheritable layout context. I've chosen the term "layout context" because it establishes additional inputs to the layout algorithm that need to be accounted for, but are not part of the geometric definition of the nodes in the scene graph themselves.
For example, consider a `VBox` with a spacing of 0.6: the gaps snap to 1.0 at render scale 1, but to 0.5 at render scale 2. Even though the size of the `VBox` and all of its inputs remain exactly the same, its children still need to move a little bit. This is especially relevant for layout containers that cache measurements or layout results (of which there are some), and makes it necessary that we have a way to invalidate those containers when the render scale or effective snapping policy changes. For this purpose, the following new APIs are added: 1. `Parent.isSnappedToPixel()` returns the effective pixel-snapping policy, which is only `true` if the node itself and all of its ancestors have their `snapToPixel` property set. All snapping methods use this method (instead of the `snapToPixel` property) to determine whether values should be snapped. 2. `Parent.layoutContextInvalidated()` will be called whenever the render scale or the effective pixel-snapping policy changes. This method can be overridden by subclasses to clear their cached measurements. Since we now have a way to invalidate the layout context, we can also cache render scales in each node instead of chasing pointers back to `Window` for every individual snapping operation. Interestingly, `Region` already cached the render scales, but in a useless way that accomplished almost nothing. Additionally, the snapping methods and the `snapToPixel` property are moved from `Region` to `Parent`, as I think having them on `Region` was always incorrect. Layout is a mechanism introduced by `Parent` (the `layoutChildren()` method is defined on `Parent`), and pixel-snapping intrinsically belongs to layout. Think about it: there can be subclasses of `Parent` that can lay out nodes, so they must also have access to pixel-snapping APIs. One such example is `Group`, which resizes its children to their preferred sizes, but is itself not a `Region`. Moving methods to a superclass is a binary- and source-compatible change. --------- - [x] I confirm that I make this contribution in accordance with the [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai). ------------- Commit messages: - line endings - inherit snapping policy - failing test Changes: https://git.openjdk.org/jfx/pull/2309/files Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=2309&range=00 Issue: https://bugs.openjdk.org/browse/JDK-8392161 Stats: 2451 lines in 30 files changed: 1723 ins; 509 del; 219 mod Patch: https://git.openjdk.org/jfx/pull/2309.diff Fetch: git fetch https://git.openjdk.org/jfx.git pull/2309/head:pull/2309 PR: https://git.openjdk.org/jfx/pull/2309
