On Tue, 30 Jan 2024 00:12:52 GMT, John Hendrikx <jhendr...@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 incrementally with one additional > commit since the last revision: > > Fix bug which confused char index with glyph index I think that it may be wise to do some clean-up of the code surrounding `TextRun` in some future PR. It's a mish-mash of things currently: - TextRun seems to be used in two ways. - The "normal" way where multiple runs are constructed from a character array, and it retains references to the start/end in that array (although not a reference to the array itself). Because it has no reference to the chars from which it was created, a lot of functionality which could be encapsulated is externalized, and many internals of `TextRun` need to be exposed to feed those external functions. - For javafx-web, which just wants to render a bunch of glyphs, unrelated to any text (so there is no character array it is based on, and its start/end values are bogus) - There is a lot of code that pretends there is a difference between a `GlyphList` (clearly intended for rendering pure glyphs only) and `TextRun`, but there is only one implementation of `GlyphList` (`TextRun`). The code that does the actual rendering in `NGText` bluntly always casts a `GlyphList` to a `TextRun`. It does this for the sole purpose of finding out the start character position of the original characters the `TextRun` was created from (needed for selection rendering), yet, for `TextRun`s created by javafx-web this is irrelevant (it just always returns `0` for the start character position). - It would have been better to do a conditional cast to `TextRun` in `NGText` so that javafx-web can use a much simpler implementation of `GlyphList` not based on `TextRun`. - In a lot of places in this code and surrounding code, fields have been failed to be marked `private` or `final` even though they can be; this may have implications for what JIT can do. - There are unused fields (`isCanonical` always returns `false`, `TextLine` is only stored to get its `RectBounds`, could just store that directly, it's `final`) A clean-up would entail: - Include a reference to the characters it was created from in `TextRun` - Encapsulate a lot of code into `TextRun` (moved from `PrismTextLayout`) that does calculations that needed both internal information of `TextRun` (that no longer needs to be exposed) and the original characters. - Have javafx-web just implement `GlyphList` and change `NGText` to work with `GlyphList`. This class would be much smaller (`TextRun` has over a dozen fields). - In `NGText` do an `instanceof` check to see if it is a `TextRun`, in which case its start offset can be used, otherwise assume it is `0`. - Mark everything final / private that can be - Remove any unused fields or fields/parameters that always have the same value (isCanonical, perhaps more) ------------- PR Comment: https://git.openjdk.org/jfx/pull/1236#issuecomment-1915835190