w3c / mathml-core

MathML Core draft
https://w3c.github.io/mathml-core
38 stars 14 forks source link

munder, mover, munderover: needs clarity in spec and consistency in implementation #213

Open NSoiffer opened 11 months ago

NSoiffer commented 11 months ago

The spec says:

The in-flow children are laid out using the algorithm for stretching operators along the inline axis.

That algorithm is:

The algorithm for stretching operators along the inline axis is as follows.

  1. If there is an inline stretch size constraint or block stretch size constraint then the element being laid out is an embellished operator. Layout the base with the same stretch size constraint.
  2. Split the list of in-flow children that have not been laid out yet into a first list LToStretch containing embellished operators with a stretchy property and inline stretch axis ; and a second list L_NotToStretch.
    1. Perform layout without any stretch size constraint on all the items of L_NotToStretch. If LToStretch is empty then stop. If L_NotToStretch is empty, perform layout with stretch size constraint 0 on all the items of L_ToStretch.
    2. Calculate the target size T to the maximum inline size of the margin boxes of child boxes that have been laid out in the previous step.
    3. Layout or relayout all the elements of L_ToStretch with inline stretch size constraint T.

I believe the text means that if both stretchy and non-stretchy elements exists, then after computing all the sizes of the children of the mover element (etc) in the non-stretch conditions, then stretch the stretchy chars to fill up the extra space. The text for '5' however says relayout the elements of L_ToStretch with the size constraint T. However, it should be that each child of mover (etc) has size constraint T and the size constraint for the elements of L_ToStretch is more complicated.

However, I'm not sure that is really what is desired and in fact, the implementations seems to be inconsistent. Here is a codepen to illustrate some differences. The following shows what happens in Chrome: image

The first example illustrates the easy case where we expect the arrow to stretch to cover the base. The second arrow mixes an identifier with the stretchy arrow. In this case, the arrow doesn't stretch which seems to be different from what the spec says should happen. The third case changes the mi to an mspace. Now the arrow stretches the full width and ends up being shifted right because of the mspace. This seems to follow what the spec says, but I believe is not at all what people expect.

I think the size constraint should be that the remaining space for each child of mover (etc) is _divided the number of elements in LToStreach for the child.

Bottom line: I think the spec is wrong and should be adjusted. But it also appears that the Chrome implementation doesn't follow the spec in all cases.

Other browsers:

dginev commented 11 months ago

Some more checks:

A curious detail in present-day implementations is that if we use an <mtext> for x in the second example, then horizontal stretching takes place in both Firefox and Chrome, but still neither will have the expected overall layout. Firefox will make the mrow a bit too wide, while Chrome will superimpose the text and the arrow.

The mspace example has a useful alternative variant via CSS padding (still with the same rendering as with Neil's 3rd screenshot).

I also tried an example with multiple stretchable <mo> arrows, which seems unsupported in either Firefox or Chrome.

codepen for these notes


I agree with the spirit of Neil's summary

I think the size constraint should be that the remaining space for each child of mover (etc) is divided by the number of elements in L_ToStreach for the child.

But I wonder if this is a big implementation change in practice? One may need the max-content inline size of the mover/munder/munderover before any stretching is calculated, to decide both where stretching is needed and what the "remaining space" is after subtracting all L_NotToStretch sizes. And this may get even more complicated if the base argument happens to reflow on a narrow viewport (assuming there will be some mechanism for "soft wrap opportunities" once we're in level-2).

dginev commented 1 month ago

This comment was moved to a Chromium report.

This is now [Chromium issue 368256337](https://issues.chromium.org/issues/368256337) I wanted to contribute an example that was reported in arXiv, which may or may not be a useful addition to the discussion - it's likely a good test case. The intended rendering is: ![Screenshot 2024-09-19 at 12-45-49 2404 02888v1 pdf](https://github.com/user-attachments/assets/4f42de7c-6df9-416f-91de-a935dc432ed8) A codepen attempt at the MathML - which in summary is an `` with a horizontal arrow base - is at: https://codepen.io/dginev/pen/KKjOewP That markup appears to work well in Firefox, but not yet in Chrome.
NSoiffer commented 1 month ago

The core spec says the arrow should stretch, so this is an implementation bug. I think it should be reported as a Chromium bug.