Skip to content
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

Specify empty <mo> treatment #209

Closed
dginev opened this issue Oct 26, 2023 · 11 comments
Closed

Specify empty <mo> treatment #209

dginev opened this issue Oct 26, 2023 · 11 comments
Labels

Comments

@dginev
Copy link

dginev commented Oct 26, 2023

We have recently started discussing generating empty <mo></mo> elements in cases where we are uncertain of which (invisible) operator was used in an expression, but have some confidence there was indeed some implied invisible operator. The main intended benefit is to avoid misleading accessibility tools in speaking the wrong information (silence often being an improvement over a mistake).

I believe that use of an empty <mo></mo> doesn't have a clear mention in MathML Core or the Operator Dictionary (unless I missed it). That is probably why it renders differently in today's Chrome and Firefox, as illustrated here:
https://codepen.io/dginev/pen/jOdbqBe

I think it would be reasonable to specify such use. Maybe it should have both lspace and rspace default to 0. And at least the way we are planning on emitting it, its form will be infix - as are most/all usual uses of the invisible Unicode chars.

As one alternative, this could be seen as unneeded complexity, and MathML Core could specify an empty <mo> is interpreted as an <mrow>, as is the usual fallback for unmet argument conditions.

@brucemiller
Copy link

brucemiller commented Oct 26, 2023 via email

@NSoiffer
Copy link
Contributor

My initial reaction is that adding am empty mo for accessibility is pointless because it tells AT nothing. However, if the point is merely to get the spacing right of an implied operator, using an mo is likely better than the alternative of adding an mspace because the mspace may cause a space in the braille that is not really merited.

Braille codes have rules about spacing around operators -- most say explicit spaces should be indicated in the braille and output should be turned in braille spaces (an empty cell). MathCAT arbitrarily picks a cutoff point and says "this is a tweak" vs "this is added space". I think I would have MathCAT decide that any lspace/rspace on an empty mo should be ignored because it would be a spacing tweak.

Bottom line: I can see some upsides to this as long as it isn't abused (e.g., two consecutive empty mos).

@dginev
Copy link
Author

dginev commented Oct 30, 2023

Discussed at the group meeting on 10/30/2023:

  • A point was raised that an empty <mo/> can be seen as a production error in generation, while having some character data looks deliberate.
  • As one recommendation for an "unknown" operator, it was suggested to use a zero-width space, character U+200B .
  • There is current mathml-core text that (also) addresses empty <mo> in 3.2.4.3 Layout of operators

    If the content of the <mo> element is not made of a single character c then fall back to the layout algorithm of 3.2.1.1 Layout of <mtext>.

    • A remark I have on this text: As currently phrased, I believe this implies that lspace and rspace attributes on an empty <mo> do not get consulted, as they are not part of the <mtext> layout algorithm. Is this actually intended? And isn't the same implied for all multi-char operators, e.g. <mo form="postfix">++</mo>?
  • As suggested, I modified the initial codepen to also mirror the examples with an <mtext> variant, so that one can easily compare the renderings.
  • The group expressed agreement that it may be useful to have new WPT tests that exercise the rendering of empty MathML elements, to ensure interop in rendering.

Edit: fix link

@dginev
Copy link
Author

dginev commented Oct 30, 2023

Brief follow-up, reading more of the spec after the meeting - I think our discussion of 3.2.4.3 Layout of operators was incomplete, since that text does not concern itself with the properties of "embellished operators", which are where lspace, rspace and form are consulted.

Notably, in 3.3.1.2 layout of mrow there is:

If the child is an embellished operator and add-space is true then increment inline-offset by its lspace property.

and similarly for rspace. An empty mo, say <mo lspace="0.2em"></mo>, is indeed an embellished operator by definition (all <mo> elements are), so its attributes will be consulted via "layout of mrow", even in the cases when "layout of operators" determines that the character data is laid out as if it were <mtext>. So the mtext examples were a bit of a misdirection.

I think we should move the focus back to whether there should be a default rule of lspace and rspace of 0 for the empty mo case (and add interop tests).

@davidcarlisle
Copy link
Collaborator

@dginev yes agreed. I noticed this while looking again at that section as well. If the content of mo is not a single character the operator ditionary and character stretching should be skipped but lspace and rspace should be honoured so the current step "layout like mtext" seems wrong.

@dginev
Copy link
Author

dginev commented Feb 2, 2024

As one recommendation for an "unknown" operator, it was suggested to use a zero-width space, character U+200B .

Can we also make U+200B act as zero-width in the operator dictionary? Currently both Firefox and Chrome add a very visible space when it is used, codepen here.

Unsure if this should be more generic, e.g. treating all Unicode "format characters" as unspaced and zero-width.

@fred-wang
Copy link
Contributor

I believe the "is not made of a single character" thing is to discard these cases for operator stretching & largeop. The corresponding data from https://learn.microsoft.com/en-us/typography/opentype/spec/math only accepts glyphs.

The lspace/rspace values are handled during https://w3c.github.io/mathml-core/#layout-of-mrow so it is correct for Firefox/Chrome to add the default lspace/rpsace 0.2777777777777778em for operators that are not in the dictionary. I believe WebKit does that too.

@fred-wang
Copy link
Contributor

As I mentioned in the past, I'm not a fan of changing again the dictionary. But the solution would be to add if length is 0 then return category K in https://www.w3.org/TR/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator or to add U+200B in that category. With current spec/implementations, one can just use an explicit lspace=0/rspace=0 though.

@fred-wang
Copy link
Contributor

For this and similar issues asking to tweak op properties, I opened #218

@MurrayIII
Copy link

MurrayIII commented Apr 18, 2024

It's easy for a user to delete the contents of an <​mi>, <​mo>, or <​mn> when editing built-up MathML in a DOM. If the element is a child of an <​mrow>, the element can be removed. But if the empty element is an argument of a MathML entity, such as the numerator of an <​mfrac>, the element cannot be removed. Unicode has a special character for an empty argument: ⬚ (U+2B1A) that can be used for such scenarios. You can see this in action by entering the fraction a/b in the output window of https://murrayiii.github.io/UnicodeMathML/playground/, clicking on the a, and hitting Delete. For this example, be sure that native MathML rendering is active. It doesn't work when MathJax is the renderer.

NSoiffer added a commit to NSoiffer/mathml-core that referenced this issue May 24, 2024
…m so that empty elements return category K (no spacing).
github-actions bot added a commit to NSoiffer/mathml-core that referenced this issue May 24, 2024
…m so that empty elements return category K (no spacing).

SHA: 31c40ab
Reason: push, by NSoiffer

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@NSoiffer
Copy link
Contributor

Resolved with commit noted above, so closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants