Skip to content

[css-ruby][css-writing-modes] Interaction of ruby with box-breaking bidirectional control codes #12327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
afishhh opened this issue Jun 12, 2025 · 0 comments
Labels
css-ruby-1 Current Work css-writing-modes-4 Current Work

Comments

@afishhh
Copy link

afishhh commented Jun 12, 2025

Context

I have a simple version of a tiny subset of CSS inline layout implemented in a project, it currently supports basic non-bidi layout of text and supports ruby annotations.

I am trying to rework this same inline layout system to support bidi (among other things), however I am very confused about what should happen if content uses bidi-voodoo to split ruby base boxes.

Box-breaking bidi

css-writing-modes explicitly mentions that bidi control codes inside text can subvert unicode-bidi isolation and that this may result in inline boxes being split.

An example of such a scenario without involving ruby boxes is:

&#X202E;<span class="a">ab</span>&#X202A;<span class="b">&#X2069;cd&#X202C;&#X202C;ef</span><br>

<style>
  html { font-size: 32pt; }
  .a { background-color: lightcoral; }
  .b { background-color: lightgreen; unicode-bidi: isolate; }
</style>

This looks like the following in all of Firefox, Chromium and Epiphany (WebKit):
Image

In this simple scenario it's obvious (and specified in this section) what should be done with the split box, it should generate separate disjoint fragments that are styled appropriately.

Base-breaking bidi (The Problem)

However in the context of ruby bases, the expected behavior is unclear. css-ruby rightfully acknowledges that splitting ruby bases doesn't make much sense and forces bidi isolation on ruby bases, but this is insufficient since the previously referenced writing-modes spec allows bypassing unicode-bidi via explicit control codes.

When presented with the following test case:

<ruby>
  &#X202E;<rb class="a">ab</rb><rt>&#X202D;one</rt><rb class="b">&#X2069;&#X202A;cd&#X202C;&#X202C;ef</rb><rt>two</rt>
</ruby>

<style>
  html { font-size: 32pt; }
  .a { background-color: lightcoral; }
  .b { background-color: lightgreen; }
  /*
     Chromium seems to behave very strangely without this set:
     - It apparently (according to window.getComputedStyle) computes `unicode-bidi` to `normal` (???) on both the <ruby> and <rb> elements.
     - Behaves as if the elements were uber-isolated (?), I can't seem to split the box in this scenario but maybe that's a bidi-code-voodoo skill issue of mine.
     Firefox doesn't seem to care much about the control codes regardless of this.
   */
  rb, rt { unicode-bidi: isolate; }
</style>

Our browsers all pick different strategies to handling this problem:

Firefox Chromium Epiphany
Image Image Image
  • In particular Chromium's strategy intrigues me the most because somehow the annotations are now in different layers and the annotation whose base was split is in an unusual position (looks like it's positioned at the start of the first fragment but centered according to the sum of the widths of the fragments).
  • Firefox seems to end up somehow still isolating the content and the layout ends up looking the same as if &#X202E;<rb class="a">ab</rb><rt>one</rt><rb class="b">cdef</rb><rt>two</rt> was inside the ruby container instead.
  • WebKit in Epiphany takes the Firefox "completely ignore the control codes" approach but places the first annotation above the first base instead of before it.

Trying to manually figure out what should happen hurts my brain but I feel like the """correct""" result would actually be a combination of Firefox's and Chromium's approaches. This is because if I got my bidi correct:

  • The second annotation will actually end up at the beginning of the text (before any bases).
  • The first one would end up after the "ab" base.

So if we assumed a model of "ruby annotation fragments apply to the base fragment directly before them after reordering" then the second annotation would apply to a virtual empty base at the start of the segment (kind of like in Firefox but with the other base) while the second one would apply to the "ab" fragment in the middle.
However I think such a model makes line breaking impossible, since we can't know how much padding we need to center the ruby base without first knowing what annotations go above it, and we can't know which ones go above it before we line-break and reorder it. (This makes me curious what Firefox does since it does seem to use the post-reordering order to pair annotations somehow?? Or actually maybe not because it's the "two" base that should get reordered to the beginning. Honestly I have no idea what's happening here.)
This is probably also why the CSSWG decided that the boxes should be isolated in the first place and why pairing operates on boxes instead of fragments (along with the fact that it wouldn't make sense from an author standpoint without isolation).

Extra fun

Somehow I managed to get Chromium to produce:
Image
(these are two separate ruby containers next to each other separated by some whitespace)
I didn't save the code for this one so there's not much to analyze but safe to say that the result is weird.

Why

I've spent wayyyy too much time thinking about how to design this new inline layout system and stuff like this keeps me up at night thinking about the appropriate course of action. I understand that this seems like a very extreme edge case that people most likely won't encounter by accident but the engine must do something in this scenario and this something does not currently seem specified (but has large consequences on the inner workings). Therefore I'd like to ask for clarification: what is supposed to happen here?

@frivoal frivoal added css-ruby-1 Current Work css-writing-modes-4 Current Work labels Jun 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-ruby-1 Current Work css-writing-modes-4 Current Work
Projects
None yet
Development

No branches or pull requests

2 participants