Bug 250969

Summary: RTL Tab handling is imperfect
Product: WebKit Reporter: Ebrahim Byagowi <ebrahim>
Component: Layout and RenderingAssignee: zalan <zalan>
Status: RESOLVED FIXED    
Severity: Normal CC: bfulgham, karlcow, koivisto, mmaxfield, simon.fraser, webkit-bug-importer, zalan
Priority: P2 Keywords: BrowserCompat, InRadar
Version: Safari Technology Preview   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=251169
Attachments:
Description Flags
Safari vs Firefox
none
Test reduction
none
Screen recording with local fix
none
fixed double selection
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch ews-feeder: commit-queue-

Description Ebrahim Byagowi 2023-01-22 03:26:03 PST
Created attachment 464591 [details]
Safari vs Firefox

Happens both in WebKit tip of tree and stable 16.2,

Reproduce:
Compare this in Safari, Chrome and Firefox

data:text/html;charset=utf8,<textarea id=textArea style="font-size: 40px; width: 1000px; font-family: Tahoma" dir=rtl></textarea><script>var i = 0; setInterval(() => { i = (i + 1) % 8; textArea.innerText = 'ش\t'.repeat(i); textArea.select() }, 1000);</script>

Note the inserted characters position, Safari apparently isn't able to handle tab in RTL correctly.

It can be seen in the attached screenshot also, distribution of spaces between letter isn't correct, the first letter is out of view.
Comment 1 zalan 2023-01-22 08:26:53 PST
Created attachment 464592 [details]
Test reduction
Comment 2 zalan 2023-01-22 08:27:28 PST
Thank you for the detailed bug report!
Comment 3 Radar WebKit Bug Importer 2023-01-22 08:27:49 PST
<rdar://problem/104528894>
Comment 4 zalan 2023-01-22 09:25:54 PST
There's at least 2 bugs here, the attached test reduction never worked in legacy line layout and modern line layout recently regressed it at 254828@main.
However I think the initial test case never worked in modern line layout and fixing 254828@main won't make it go away. Will file a separate bugzilla on it.
Comment 5 zalan 2023-01-22 09:39:04 PST
ok, it looks like "unicode-bidi: isolate" is the culprit here. It's the combination of white-space: pre (for preserving trailing tab) and "isolate" (<- incorrect positioning),
where the non-isolate case recently regressed (see above) and the isolate case never worked in modern line layout (IFC).
Comment 6 zalan 2023-01-22 13:26:16 PST
Created attachment 464596 [details]
Screen recording with local fix

it looks like it's about incorrect bidi level on trailing whitespace (tab) runs. Screen recording is with local fix.
Comment 7 Ebrahim Byagowi 2023-01-22 22:31:18 PST
> Screen recording is with local fix.

Looks good except that double highlighting which I wish they can go also, feel free to post the patch here so I can help on verifying whether it doesn't regress any other case and covers all the issues I'm seeing with tab.
Comment 8 zalan 2023-01-23 08:04:25 PST
(In reply to Ebrahim Byagowi from comment #7)
> > Screen recording is with local fix.
> 
> Looks good except that double highlighting which I wish they can go also,
> feel free to post the patch here so I can help on verifying whether it
> doesn't regress any other case and covers all the issues I'm seeing with tab.
Thank you! (will be posting the patch soon, it just needs some more work)
Comment 9 zalan 2023-01-23 13:32:55 PST
> Thank you! (will be posting the patch soon, it just needs some more work)
Actually I need to talk with Myles first before posting a patch. We may need to address this in ComplexTextController.

Let's take the following example: "&#1588;	" where the inline direction is right-to-left.
1. During layout (at this point we are in logical space), first we measure &#1588;, followed by the tab character.
2. By the time we measure the tab character we already advanced to position X (where X is the (logical) right edge of the measured &#1588; glyph, let's ignore content box offsets for now.)
3. tab character width is horizontal position dependent. At position X, we measure it to be W.
4. Now at paint time, we take the tab glyph first (it's visually the first glyph), and measure it at position 0. 
This measured width may be very different from W due to the difference in X position. (and this is what's causing this bug).

Now the difference between legacy and IFC is that IFC merges runs whenever possible. In this case legacy constructs dedicated run for the trailing (visually leading) tab character.
With dedicated runs, we paint each glyphs at explicit positions computed during layout (e.g [tab] at 0px, [&#1588;] at 50px vs [tab&#1588;] at 0px)
ComplexTextController still computes incorrect advanced width for the tab character, but with explicit run positions it's mostly unnoticeable (unless you select the content and get double highlights).
Soon after pre-wrap is changed to pre, legacy mergers runs and the bug shows.

We could address this in IFC by always constructing dedicated trailing tab runs, but it would not address the selection issue.
Comment 10 zalan 2023-01-23 19:55:44 PST
Created attachment 464624 [details]
fixed double selection

This is with dedicated runs and logical tab position at paint time.
Comment 11 Ebrahim Byagowi 2023-01-23 20:42:30 PST
> fixed double selection

This looks great.

> is horizontal position dependent

Oh, now I see the issue also.

As said I like to get more involved with the development of the fix here, yet, I feel that causes more hassle to you so instead I just like to express that I'm very happy that WebKit's text rendering is getting a proper love it deserves, (also this isn't to rush anything, a proper fix indeed takes considerable time to be correctly figured out then applied)

So, thanks 😊
Comment 12 zalan 2023-01-24 16:21:57 PST
(In reply to Ebrahim Byagowi from comment #11)
> > fixed double selection
> 
> This looks great.
> 
> > is horizontal position dependent
> 
> Oh, now I see the issue also.
> 
> As said I like to get more involved with the development of the fix here,
> yet, I feel that causes more hassle to you so instead I just like to express
> that I'm very happy that WebKit's text rendering is getting a proper love it
> deserves, (also this isn't to rush anything, a proper fix indeed takes
> considerable time to be correctly figured out then applied)
> 
> So, thanks 😊
:) thank you! I really appreciate that you are willing to take the trouble to apply the patch locally and run regression testing! So awesome.
Comment 13 zalan 2023-01-25 13:01:05 PST
Created attachment 464654 [details]
Patch
Comment 14 zalan 2023-01-25 13:02:54 PST
Filed bug 251169 for the overlapping selection issue.
Comment 15 zalan 2023-01-25 18:59:19 PST
Comment on attachment 464654 [details]
Patch

Needs rebaselining.
Comment 16 zalan 2023-01-25 20:59:28 PST
Created attachment 464665 [details]
Patch
Comment 17 zalan 2023-01-26 07:07:30 PST
Created attachment 464668 [details]
Patch
Comment 18 EWS 2023-01-26 09:06:29 PST
Committed 259428@main (7b94b0c936fb): <https://commits.webkit.org/259428@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 464668 [details].
Comment 19 Ebrahim Byagowi 2023-01-26 22:44:45 PST
I tested tabs in RTL with tip of tree (5dc808f) and everything works as expected. Thank you very much 😊
Comment 20 zalan 2023-01-27 20:17:17 PST
(In reply to Ebrahim Byagowi from comment #19)
> I tested tabs in RTL with tip of tree (5dc808f) and everything works as
> expected. Thank you very much 😊
Awesome! Thank you for confirming it!