RFR: JDK-8314215 Trailing Spaces before Line Breaks Affect the Center Alignment of Text [v11]

John Hendrikx jhendrikx at openjdk.org
Fri Feb 9 01:36:05 UTC 2024


On Wed, 7 Feb 2024 15:06:18 GMT, John Hendrikx <jhendrikx at openjdk.org> wrote:

>> There are a number of tickets open related to text rendering:
>> 
>> https://bugs.openjdk.org/browse/JDK-8314215
>> 
>> https://bugs.openjdk.org/browse/JDK-8145496
>> 
>> https://bugs.openjdk.org/browse/JDK-8129014
>> 
>> They have in common that wrapped text is taking the trailing spaces on each wrapped line into account when calculating where to wrap.  This looks okay for text that is left aligned (as the spaces will be trailing the lines and generally aren't a problem, but looks weird with CENTER and RIGHT alignments.  Even with LEFT alignment there are artifacts of this behavior, where a line like `AAA  BBB  CCC` (note the **double** spaces) gets split up into `AAA  `, `BBB  ` and `CCC`, but if space reduces further, it will wrap **too** early because the space is taken into account (ie. `AAA` may still have fit just fine, but `AAA  ` doesn't, so the engine wraps it to `AA` + `A  ` or something).
>> 
>> The fix for this is two fold; first the individual lines of text should not include any trailing spaces into their widths; second, the code that is taking the trailing space into account when wrapping should ignore all trailing spaces (currently it is ignoring all but one trailing space).  With these two fixes, the layout in LEFT/CENTER/RIGHT alignments all look great, and there is no more early wrapping due to a space being taking into account while the actual text still would have fit (this is annoying in tight layouts, where a line can be wrapped early even though it looks like it would have fit).
>> 
>> If it were that simple, we'd be done, but there may be another issue here that needs solving: wrapped aligned TextArea's.
>> 
>> TextArea don't directly support text alignment (via a setTextAlignment method like Label) but you can change it via CSS.
>> 
>> For Left alignment + wrapping, TextArea will ignore any spaces typed before a line that was wrapped.  In other words, you can type spaces as much as you want, and they won't show up and the cursor won't move.  The spaces are all getting appended to the previous line.  When you cursor through these spaces, the cursor can be rendered out of the control's bounds.  To illustrate, if you have the text `AAA                 BBB CCC`, and the text gets wrapped to `AAA`, `BBB`, `CCC`, typing spaces before `BBB` will not show up.  If you cursor back, the cursor may be outside the control bounds because so many spaces are trailing `AAA`.
>> 
>> The above behavior has NOT changed, is pretty standard for wrapped text controls,...
>
> John Hendrikx has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 16 additional commits since the last revision:
> 
>  - Merge branch 'openjdk:master' into feature/wrapped-aligned-text-rendering
>  - Fix test comment
>  - More test cases (for hard wrapping) and another small fix
>  - Improve tests, fix a bug
>  - Fix bug which confused char index with glyph index
>  - Move test that needs QuantumToolkit to system tests
>  - Clean-up, re-enable and extend ancient TextLayout test
>  - TextRun getAdvance should return 0 when positions array is null
>  - Fix justify alignment to take all trailing spaces into account
>  - Fix trailing space calculation to access positions array directly
>  - ... and 6 more: https://git.openjdk.org/jfx/compare/c1e97be2...388696a6

I fixed the slight inaccuracies surrounding the float/double conversion but it didn't fix the flickering scrollbar.

My theory is now that how the wrap width of the `Text` node is updated is not entirely legal (I posted on the mailinglist to see if anyone can remember how this is supposed to work when you update a value (that may cause layout changes) based on a property that is already changed by layout code).

What I'm thinking is that `ScrollPane.viewportBoundsProperty`, which is only set in `layoutChildren` of its skin, should not be bound to the `Text` wrapping width -- a layout is already running, and updating another property that will affect layout will result in undefined behavior.  I see the same issue when I bind that value to a simple `Label`'s text -- the text width is often incorrect resulting in an ellipsis being displayed.  So I'm thinking the reason the horizontal scroll bar appears on the `ScrollPane` is because the bounds it calculated were based on the previous `Text`'s wrapping width, and is not recalculated again when we update the `Text` wrapping width **during** layout.

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

PR Comment: https://git.openjdk.org/jfx/pull/1236#issuecomment-1935203621


More information about the openjfx-dev mailing list