This was failing 10 steps away from the actual problem due to
propagation of weird float values (infinities, NaNs, etc.) The actual
problem was that the offset logic was doing questionable things when the
flow was doing initial autosizing in the X direction. In that case the
maximum width was initialised to `float.MaxValue`, which then in
subsequent calculations got reduced to a very-large-but-finite X
position of everything in the flow, and things just broke.
To circumnavigate that, initialise max size using saner
`float.PositiveInfinity` values (which can be used as markers later),
store the actual widths of the lines rather than the offsets to the
right, and then in the second pass, account for the infinite expansion
due to autosize case by overwriting the max width with the width of the
broadest row.
Fixes
https://discord.com/channels/90072389919997952/1327149041511043134/1351809773510590494.
Essentially what's happening here is that new lines have weird sizing
rules wherein the height of the new line is relative to the height of
the line preceding it. https://github.com/ppy/osu-framework/pull/6545
broke this because prior to it, the lines responsible for this, namely
769a5d5803/osu.Framework/Graphics/Containers/TextFlowContainer.cs (L448-L452)
ran in `TextFlowContainer.UpdateAfterChildren()` before the `base` call,
and because `TextFlowContainer` inherited `FillFlowContainer`, changing
the inheritance to composition essentially reordered the call so that
the height set happened *after* `FillFlowContainer`'s layout logic ran,
which is why the layout could be essentially wrong for a frame (with the
new lines having height of zero).
After several hours of trying several hacks to jam this behaviour back
where it should be, I noticed that the entire flow was just broken even
before I started touching it. There were two completely independent
invalidation paths (one in fill flow, one in text flow), and even before
any of my recent changes, when (ab)using some rarely-used features like
first line indent you could provoke the text flow to start twitching.
So what this does is that it takes the entirety of
`ComputeLayoutPositions()` from fill flow, and adapts it to actually
properly handle all of the features that text flow needs without
post-facto position or margin adjusting hacks.
Fixes one part of https://github.com/ppy/osu/issues/32348.
The reason this is required is due to the game-side abuse done by
`DrawableLinkCompiler` & co. See the following:
4633f635a4/osu.Game/Graphics/Containers/LinkFlowContainer.cs (L141-L144)
`FillFlowContainer` performs layout computations on `FlowingChildren`
specifically:
1ccf0376c4/osu.Framework/Graphics/Containers/FillFlowContainer.cs (L113)
Because of this, if using `Flow.Children` in `TextFlowContainer`, the
`DrawableLinkCompiler` - which was skipped by the inner fill flow - is
now being considered for layout at the text flow level. Text flow sees
that the X position of the compiler is 0 (because it wasn't touched by
the inner fill flow), and thus thinks it must be a line break, which
it's not.
So we use `FlowingChildren` to restore parity.
In line with other changes, this should have been switched to `double`.
Also making `virtual` for usage within the beatmap carousel (I need to
extend what this function does for this usage).
This is the first step towards supporting scrolling over very large
amounts of content. With this along, the animation already becomes
somewhat smoother (no longer "locking" into place too early) but scroll
content will still look jagged when scrolled too far down.
Fixing actual content requires a small amount of extra implementation on
top of this. To keep things simple this would be up to the consumer to
implement and maintain.
Intended to help fix osu! song select from becoming weird when hundreds
of thousands of beatmaps are loaded.