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

percentage of minsize/maxsize #103

Closed
fred-wang opened this issue Jul 15, 2021 · 24 comments
Closed

percentage of minsize/maxsize #103

fred-wang opened this issue Jul 15, 2021 · 24 comments

Comments

@fred-wang
Copy link
Contributor

From MathML Core: "Percentages value for minsize and maxsize properties of an embellished operator are interpreted relative to the target stretch size before application of size constraints, as described in § 3.3.1.1 Algorithm for stretching operators along the block axis. "

This is not really clear.

The current version of the spec says "Let minsize and maxsize be the minsize and maxsize properties on the operator. Percentage values are intepreted relative to T = Tascent + Tdescent"

So it should really refer to section https://w3c.github.io/mathml-core/#layout-of-operators

@fred-wang
Copy link
Contributor Author

Additionally, default minsize of "100%" does not work with the current definition as this overrides maxsize. So I guess it should instead be 1em or 0.

@brucemiller
Copy link

Sorry I missed this when it went by before, but "relative to the target stretch size" is in marked contrast to MathML Full's "multipliers of the operator's normal size" (ie. the unstretched size; See https://w3c.github.io/mathml/spec.html#presm_op_stretch).

Was this an intentional change? Should this issue be reopened, or a new one?

@dginev
Copy link

dginev commented Jan 9, 2023

@fred-wang I second Bruce's question.

Also, when the behavior is finalized, I would also like to request an example in the MathML Core text that walks through the steps to compute the absolute size when starting with the percentage value of maxsize/minsize.

The current text is a bit hard to follow for me (and it wasn't immediately clear if it applies to all <mo> cases or only "If the operator has the stretchy property").

Here are two minimal examples that helped me appreciate the nuances with the containing row, though they don't render quite right yet - but maybe that is an independent issue:

https://codepen.io/dginev/pen/GRemwwr

Edit: replaced the gist with a codepen, easier to compare the difference between Firefox and Chrome.

@NSoiffer
Copy link
Contributor

I see that the respec version of the core spec shows five tests, but none test min/max size. There is one such test (which is actually 6 tests), so the spec should link to that also.

On that test, Chrome scores a 6, Safari a 5, and Firefox 0. Most of the tests are about edge cases (e.g., minsize <0, maxisze < minsize). The Safari failure is on "minsize/maxsize percentages are relative to the target size", so it could well be that the core spec doesn't reflect what was implemented elsewhere (and certainly differs from MathML full).

I'm reopening because this difference should be discussed.

@NSoiffer NSoiffer reopened this Jan 10, 2023
@brucemiller
Copy link

It would be good if a test verified that symmetric=true is respected when minsize and/or maxsize are given.

@NSoiffer
Copy link
Contributor

@brucemiller: anyone (including you) can add tests...

@dginev
Copy link

dginev commented Feb 24, 2024

I have been asked by arXiv to raise awareness of the impact of this issue, cross-referencing arXiv/html_feedback#354 (comment)

Edit: Adding a codepen with a self-contained equation from the arXiv report:
https://codepen.io/dginev/pen/ExMqyLd

@bkardell
Copy link
Collaborator

bkardell commented Feb 27, 2024

I love the pens for people to try, but also some might not be able to check certain browsers easily and the results can change over time which can make it confusing if the issue is open very long, so ... Below is a screen grab of @dginev's pen opened in 3 browsers side by side. From left to right: Firefox, Chrome, Safari

Screenshot 2024-02-27 at 11 00 10 AM

@brucemiller
Copy link

Given the several browser quirks, particularly the unsymmetric "|", 90% may be a bit too subtle to appreciate the effect of minsize, maxsize. This more artificial example shows Firefox (left) tracking MathML Full; Chrome (middle) tracking MathML Core and Safari (left) apparently ignoring percentages in minsize, maxsize:
percent

@brucemiller
Copy link

Core currently specifies that percentages in minsize/maxsize are "Percentage values are interpreted relative to T = Tascent + Tdescent." where T is apparently the target, ie. stretched, size of the glyph.

This is an incompatible change from MathML 2 & 3 (at least). Although the current MathML Full spec sometimes refers simply to percent as relative to "normal" size, which apparently allows for some (mis)interpretation), in most other places it is explicit.
See https://w3c.github.io/mathml/spec.html#dictionary-based-attributes
"Unitless or percentage values indicate a multiple of the reference size, being the size of the unstretched glyph."

Consequently we have two options:

  • change MathML Full to match MathML Core, and look for future patches to Firefox (& Safari)
  • revert MathML Core to match MathML Full, and look for future patches to Chrome (& Safari)

Before pushing for either of those two options, it would be good to understand whether the changed behavior specified by Core was intentional, and the reasoning behind it. It is hard for me to see the use-case; OTOH, in the current Full spec, percentage, dimensionless numbers and em units are somewhat redundant. (unitless was not carried over into Core)

@bkardell
Copy link
Collaborator

bkardell commented Mar 26, 2024

The WG discussed this yesterday, minutes follow

DG: The main question is a choice toggle of how you intrepret a percentageof minsize and maxsize. Is the base for the percentage unstretched or stretched size.
we want to align mathml 4 and mathml core.

FW (relayed by BK): I would need to check this one. I don't have a strong preference as a user. But as an implementer, just want to make sure we are not introducing something that violates browser's layout model or complicates the implementation needlessly (that might be the reason of the change, but not can't remember)? At glance, it seems quite easy to get calculate a percent of the target size while during layout for the other option we would have to calculate a percent of the unstretch size of a core operator (which can be deep in the tree due to embellished op and so on). Would be worth giving a try with Chromium...

NS: we need to be governed by what is implementable. It is possible that Fred made the same mistake that David and I made about thinking it was referencing the stretched size... or not.

BM: it could be CSS convention that causes the confusing.

DG: In CSS, max-height, min-width, etc refer to the parent.

NS: How much will break if we change the spec?

BM: In DLMF, specific sizes are not used much but growable sizes look better IMHO.

DG: ar5iv 2024 stats:
mo: 4,704,693,527
mo with maxsize set (always % in latexml): 69,820,857

From Brian Kardell to Everyone: HTTPArchive/almanac.httparchive.org#3619 ... actually, maybe disregard, that wouldn't be good as a data source because it is biased away from stuff with math to begin with even.

bk: if you have further thoughts share them on the issue and let fred how important his is.

@fred-wang
Copy link
Contributor Author

fred-wang commented Mar 28, 2024

Hi, so I get a chance to look this into more details.

For reference, current implementations are here:

Firefox: https://searchfox.org/mozilla-central/rev/b4860b54810539f0e4ab1fc46a3246daf2428439/layout/mathml/nsMathMLmoFrame.cpp#619

WebKit: https://searchfox.org/wubkat/rev/3180ee0bf2d7f95d1d938b55546a3ef50eb2b9b6/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp#124

Chromium: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/layout/mathml/math_operator_layout_algorithm.cc;l=71;drc=18e5fcceb38d3cb42ba12379c08b698df9592876

First, I stand corrected about the complexity. All the implementations handle the calculation in the layout classes for the mo element. In the past, the minsize/maxsize resolution was handled in https://w3c.github.io/mathml-core/#algorithm-for-stretching-operators-along-the-block-axis but later I moved this to https://w3c.github.io/mathml-core/#layout-of-operators to simplify things.

So for this issue we can just replace "Percentage values are interpreted relative to T = Tascent + Tdescent" with "Percentage values are interpreted relative to the unstretched size" (maybe definining it more precisely as the height of the bounding box of glyph corresponding to c).

Bruce mentioned some links to MathML full and even if "normal" can be confusing, I believe the "unstreched size" is clearer. I can't remember why this was done that way in MathML Core, maybe because of this unclear "normal" wording or maybe because in the past this was done in another place where the unstretched size couldn't be easily retrieve.

From a user point of view, taking a percent of the target size also means targetting a different size which is probably not what we want? I can imagine the use of 105% to say make things slightly taller but 200% would mean introducing big gaps. I see that font units (e.g. 3em) allows to approximate multiple of the unstretched size (e.g. 300%) but probably one wants more accuracy.

Regarding the "symmetric" property, all browsers and MathML Core do that before applying the minsize/maxsize constraints. Applying "symmetric" can increase the size (multiplying it by a factor between one and two), so 1) if minsize would be applied before it could make the character unnecessarily big and 2) we can't apply the maxsize constraint before, without garanteeing it won't be violated later by symmetrization.

It also seems all browsers and current MathML Core spec are wrong, since they somehow trying to apply scaling using the baseline as a reference rather the math axis. Step 5 can just be corrected by a coordinate change :

  • If T ≤ 0 then set Tascent to minsize / 2 + AxisHeight and then set Tdescent to minsize − Tascent.
  • Otherwise, if 0 < T < minsize then set Tascent to (Tascent - AxisHeight) * minsize / T + AxisHeight and Tdescent to minsize - Tascent.
  • Otherwise, if maxsize < T then set Tascent to (Tascent - AxisHeight) * maxsize / T + AxisHeight and Tdescent to maxsize - Tascent.

If symmetrization happened in step 4, then at step 5 we have:

Tascent − AxisHeight = Tdescent + AxisHeight = T/2

and after applied the minsize/maxsize constraints this equality remains true (T is respectively minsize, minsize and maxsize for the three bullets) so the operator remains symmetric with respect to the math axis.

Note that the math axis is generally small for normal math fonts so this difference is not really observable in practice. Still, we can write tests with math fonts that have large AxisHeight in order to test that more precisely.

@fred-wang
Copy link
Contributor Author

Testcase:

<!DOCTYPE html>
<link
  rel="stylesheet"
  href="https://fred-wang.github.io/MathFonts/LatinModern/mathfonts.css" />
<style>
  math { font-size: 32pt; }
  mfrac { color: red; }
  mfrac > * { color: blue; }
</style>
<body>
  <p>
    symmetric=false, minsize=300%
    <math displaystyle="true">
      <mo symmetric="false" minsize="300%">(</mo>
      <mfrac>
	<msup><mn>3</mn><msup><mn>4</mn><mn>5</mn></msup></msup>
	<mn>222</mn>
      </mfrac>
    </math>
  </p>
  <p>
    symmetric=false, minsize=3em
    <math displaystyle="true">
      <mo symmetric="false" minsize="3em">(</mo>
      <mfrac>
	<msup><mn>3</mn><msup><mn>4</mn><mn>5</mn></msup></msup>
	<mn>222</mn>
      </mfrac>
    </math>
  </p>
  <p>
    symmetric=true, minsize=300%
    <math displaystyle="true">
      <mo symmetric="true" minsize="300%">(</mo>
      <mfrac>
	<msup><mn>3</mn><msup><mn>4</mn><mn>5</mn></msup></msup>
	<mn>222</mn>
      </mfrac>
    </math>
  </p>
  <p>
    symmetric=true, minsize=3em
    <math displaystyle="true">
      <mo symmetric="true" minsize="3em">(</mo>
      <mfrac>
	<msup><mn>3</mn><msup><mn>4</mn><mn>5</mn></msup></msup>
	<mn>222</mn>
      </mfrac>
    </math>
  </p>
</body>

@fred-wang
Copy link
Contributor Author

@brucemiller
Copy link

This looks fantastic! Thanks for digging into this @fred-wang !!

Personally, I can live with the subtle differences in the unsymmetric cases, since I'm never completely sure what I expect there anyway :>

@fred-wang
Copy link
Contributor Author

Regarding the tests, the only one affected by the change is https://chromium-review.googlesource.com/c/chromium/src/+/5402478/2/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/mo-minsize-maxsize-001.html#118

I'm not sure we have a test to verify symmetric=true + minsize/maxsize in general, so will try to add one with the AxisHeight subtility.

@NSoiffer
Copy link
Contributor

Sounds like we have a resolution. I've added the "needs specification update" label. From what @fred-wang wrote, there are two changes:

  1. So for this issue we can just replace "Percentage values are interpreted relative to T = Tascent + Tdescent" with "Percentage values are interpreted relative to the unstretched size" (maybe definining it more precisely as the height of the bounding box of glyph corresponding to c).

  2. If T ≤ 0 then set Tascent to minsize / 2 + AxisHeight and then set Tdescent to minsize − Tascent.

    • Otherwise, if 0 < T < minsize then set Tascent to (Tascent - AxisHeight) * minsize / T + AxisHeight and Tdescent to minsize - Tascent.
    • Otherwise, if maxsize < T then set Tascent to (Tascent - AxisHeight) * maxsize / T + AxisHeight and Tdescent to maxsize - Tascent.

      If symmetrization happened in step 4, then at step 5 we have:

      Tascent − AxisHeight = Tdescent + AxisHeight = T/2

      and after applied the minsize/maxsize constraints this equality remains true (T is respectively minsize, minsize and maxsize for the three bullets) so the operator remains symmetric with respect to the math axis.

@fred-wang
Copy link
Contributor Author

Thanks. If there is no complaints, I will go ahead and work on spec/tests/impl as soon as I have time (hopefully later this week).

@fred-wang
Copy link
Contributor Author

There is one note about the interpretation of maxsize ∞ that should be moved closer if possible, and I would also add a note about the fact that scaling for maxsize/minsize is done with respect to the math axis, hence preserving any previous symmetry from step 4.

fred-wang added a commit that referenced this issue Apr 3, 2024
- Make sure the percentages of minsize/maxsize are handled with respect to the unstretched size, as that was the case in MathML 3.
- Make sure minsize/maxsize adjustments preserve symmetry with respect to the math axis.
- Add some notes (non-normative) explaining the symmetric, minsize and maxsize adjustments.
github-actions bot added a commit that referenced this issue Apr 3, 2024
SHA: 5d2bf69
Reason: push, by fred-wang

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

I pushed a commit to apply the discussed changes above as well as more notes explaining these steps.

Note that MathML full was also scaling with respect to the baseline (rather than the math axis) so it was not respecting the symmetric rule either: "If the total size = height+depth is less than minsize or greater than maxsize, increase or decrease both height and depth proportionately so that the effective size meets the constraint. "

@fred-wang
Copy link
Contributor Author

fred-wang commented Apr 3, 2024

There seem to be another change that happened: in MathML full minsize default to 100% while in MathML Core, it defaults to 1em. But it's likely 1em is larger than 100% the unstretched size, so MathML Core would always do scaling adjustment to ensure target size is at least 1em. I guess this was related to this issue regarding interpretation of percentage, but now we fixed that we can go back to a default minsize of 100%. I haven't checked yet, but maybe this can explain things like #205 (comment)

Another thing we might revise is the case T ≤ 0. edit: moved to #230

@fred-wang
Copy link
Contributor Author

So just to be clear I'm proposing to replace 1em with 100% here, so it matches MathML Full: https://w3c.github.io/mathml-core/#dfn-algorithm-to-set-the-properties-of-an-operator-from-its-category

For T ≤ 0, the right thing to do is less clear so I guess we can handle that in a separate issue.

@fred-wang
Copy link
Contributor Author

https://chromium-review.googlesource.com/c/chromium/src/+/5402478 has been updated to match the current spec and increase test coverage.

fred-wang added a commit that referenced this issue Apr 5, 2024
This is consistent with MathML 3 and works as desired now that percentages
are interpreted relative to the unstretched size.
github-actions bot added a commit that referenced this issue Apr 5, 2024
SHA: c987737
Reason: push, by fred-wang

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 5, 2024
This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 6, 2024
This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402478
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1283539}
aarongable pushed a commit to chromium/chromium that referenced this issue Apr 6, 2024
This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402478
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1283539}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 6, 2024
This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402478
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1283539}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 6, 2024
This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402478
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1283539}
@fred-wang
Copy link
Contributor Author

Tests updated/added in web-platform-tests/wpt#45572

and the spec is updated too, so closing this.

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Apr 15, 2024
Automatic update from web-platform-tests
[mathml] minsize/maxsize

This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402478
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1283539}

--

wpt-commits: 23894a7e427bc088cfd4b3aa6ba8a8927b904713
wpt-pr: 45572
ErichDonGubler pushed a commit to ErichDonGubler/firefox that referenced this issue Apr 16, 2024
Automatic update from web-platform-tests
[mathml] minsize/maxsize

This is implementing changes discussed in [1]:

- percentage minsize/maxsize should refer to the unstretched size,
  mo-minsize-maxsize-001.html is updated accordingly.

- minsize/maxsize adjustments are done by scaling the distance
  above and below the math axis proportionally.
  mo-axis-height-1.html is extended to verify calculations from
  [2]. These new formulas ensure that symmetry with respect to
  the math axis is preserved when minsize/maxsize is applied
  and two tests are added to verify that more directly.

- default value for minsize is 100% (the unstretched size) rather
  than 1em.

[1] w3c/mathml-core#103
[2] https://w3c.github.io/mathml-core/#layout-of-operators

Bug: 332931380
Change-Id: I63ca77c5d0b8934570916d589160da0c90722f08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402478
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1283539}

--

wpt-commits: 23894a7e427bc088cfd4b3aa6ba8a8927b904713
wpt-pr: 45572
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants